Vue3_Project更新中

Vue-Cli3 + Node Project

項(xiàng)目展示以及技術(shù)棧

NodeJS構(gòu)建后端接口 VueCli3.0構(gòu)建前端頁(yè)面

  1. 構(gòu)建接口文檔:Node + express + jwt
  2. 構(gòu)建前端頁(yè)面:VueCli3.0 + Elemenet-ui
  3. 數(shù)據(jù)請(qǐng)求及攔截 : Axios + Mlab + MongoDB
  4. 分頁(yè)和篩選
  • 可以掌握的技能點(diǎn):
    • 全站開發(fā)的項(xiàng)目經(jīng)驗(yàn)
    • Token處理
    • 請(qǐng)求和響應(yīng)攔截
    • 組件封裝

Node 接口搭建

express 搭建服務(wù)器

  • cd到項(xiàng)目文件夾下 初始化一個(gè) package.json

    • npm init 會(huì)讓選擇名字 描述:restful api
    • 入口文件的名字 默認(rèn)index.js 也可以更換名字
    • 然后一路回車就可以了
  • cttl + ~ 可以打開 這個(gè) VSCode 的 npm 控制臺(tái)

  • touch server.js 然后就創(chuàng)建了一個(gè) server.js 的文件

  • 借助 express 框架搭建我們的 服務(wù)器

    • 安裝 npm install express -S

    • 然后 具體在 server.js 中的代碼如下:

      const express = require("express");
      const app = express();
      
      app.get("/",(req,res) => {
          res.send("Hello World~");
      })
      
       // 端口號(hào)
      const port = process.env.PORT || 5000;
      
      app.listen(port,() => {
          console.log(`Server running on port ${port}`);
      })
      
    • 然后 node server.js 就可以了

    • 然后是 為了 不一直重啟 所以就 安裝 nodemoncnpm i nodemon -G

      然后nodemon server.js 就可以了

  • 然后在 package.json 里面可以設(shè)置:

    "script" : {
        "start" : "node server.js",       // 上傳上線的時(shí)候 會(huì)有一個(gè) start
        "server" : "nodemon server.js"    // 這個(gè)是本地測(cè)試的時(shí)候啟動(dòng)的
    }
    
  • 然后運(yùn)行 npm run start 就可以運(yùn)行了

    • 這種情況下 就是 每次寫完代碼就需要重啟
    • 然后在開發(fā)環(huán)境下的話 運(yùn)行 npm run server 就可以了

連接MongoDB 數(shù)據(jù)庫(kù)

mLab部分

  • 在這個(gè)項(xiàng)目課程當(dāng)中 連接的就是 線上的 mLab mongodb 數(shù)據(jù)庫(kù)

    然后注冊(cè)完成后 會(huì)給一個(gè) 500M 的使用權(quán)(個(gè)人開發(fā)完全夠用)

  • 新建的時(shí)候 選擇 amazon 然后選擇 SANDBOX 然后 CONTINUE

    • 然后選擇 區(qū)域 美國(guó) US East 然后設(shè)置名字 點(diǎn)擊CONTINUE 點(diǎn)擊 SUBMIT
  • 進(jìn)入之后 有一個(gè) Users 創(chuàng)建 不勾選 Make read-only

  • 然后 就可以看到 上面有一個(gè) mongodb 的地址了 這個(gè)地址就可以存儲(chǔ)和讀取數(shù)據(jù)了

接下來(lái)是代碼部分

  • 下載一個(gè) cnpm install mongoose -S

    server 下面引入mongoose

     // server.js文件下的內(nèi)容
    const mongoose = require("mongoose"); 
    
    // DB config      如果是本地的就是本地的URI不是就是網(wǎng)絡(luò)的
    const db = require("./config/keys").mongoURI;
    
    // Connect to mongodb     提供了promise提供了.then 
    mongoose.connect(db)
      .then( ()=>console.log("MongoDB Connected") )
      .catch( err=>console.log(err) )
    
  • 在根目錄下面創(chuàng)建一個(gè)文件夾 config 創(chuàng)建一個(gè) keys.js

    // keys.js下面的內(nèi)容
    module.exports = {
        mongoURI : "就是剛剛mLab復(fù)制的地址"  // 里面的user和password 更改為自身創(chuàng)建的mLab賬號(hào)密碼
    }
    

搭建接口 - 路由和數(shù)據(jù)模型

  • 根目錄創(chuàng)建文件夾 routes 里面新建一個(gè) api 文件夾 新建一個(gè) users.js

    // users.js文件下的內(nèi)容
    // @login & register
    const express = require("express");
    const router = express.Router();
    
    // $route GET api/users/test
    // @desc  返回請(qǐng)求的json數(shù)據(jù)
    // @access  public
    router.get("/test",(req,res) => {
        res.json({msg:"login works"})   // 這個(gè)就是向?yàn)g覽器返回一個(gè)json數(shù)據(jù)
    })
    
    module.exports = router;
    
  • 然后再 server.js 中補(bǔ)充添加路由相關(guān)的引用

    // 引入user.js
    const users = require("./routes/api/users")
    
    // 使用 routes  在端口號(hào)下面 添加使用中間件
    app.use("/api/users",users)
    
  • 然后創(chuàng)建一個(gè) modules 的文件夾 在下面創(chuàng)建一個(gè) User.js 的文件

    // User.js
    const mongoose = require("mongoose");
    const Schema = mongoose.Schema;
    
    // Create Schema
    const UserSchema = new Schema({
        name : {
            type : String,
            required : true
        },
        email : {
            type : String,
            required : true
        },
        password : {
            type : String,
            required : true
        },
        avatar : {    // 頭像
            type : String
        },
        date : {
            type : Date,
            default : Date.now
        }
    })
    
    module.exports = User = mongoose.model("users",UserSchema);
    

搭建注冊(cè)接口并存儲(chǔ)數(shù)據(jù)

本地測(cè)試接口的一個(gè)工具 注冊(cè)接口 第三方頭像的一個(gè)庫(kù)

  • 測(cè)試本地接口的一個(gè)工具 postman 進(jìn)入官網(wǎng)下載app

  • 然后進(jìn)行 注冊(cè)登錄

  • Get 之后的 URL 中 輸入后臺(tái)調(diào)試的接口地址。

  • 搭建一個(gè) 注冊(cè) 接口

    // users.js  
    // $route POST api/users/register
    // @desc  返回請(qǐng)求的json數(shù)據(jù)
    // @access  public
    router.post("/register",(req,res) => {
        console.log(req.body);
    })            // 如果要使用 post 請(qǐng)求 就需要安裝 body-parser
    
  • 然后在 server.js 注冊(cè)引入就好啦

    const bodyParser = require("body-parser");
    
    // 然后使用一個(gè)body-parser的中間件
    app.use(bodyParser.urlencoded({extended:false}));
    app.use(bodyParser.json());
    // 然后回到 users.js
    
  • 這樣在 postman 里面就有然后選擇類型 post

    然后選擇 body 里面的 x-www-form-urlencoded 然后在 Header 里面就會(huì)自動(dòng)添加

    在 Body里面 key里面 添加數(shù)據(jù) key(email) 然后再value里面 添加數(shù)據(jù) values(test@test.com)

    然后 send發(fā)送就可以了 在node里查看就可以了~( console.log(req.body) )

     // users.js下面內(nèi)容
    const User = require("../../models/User");
    const bcrypt = require("bcrypt")
    
    router.post("/register",(req,res) => {
        // 查詢數(shù)據(jù)庫(kù)中是否擁有郵箱
        User.findOne({email : req.body.email})
            .then((user) => { //然后就會(huì)返回一個(gè) user
            if(user){
                return res.status(400).json({
                    email : "郵箱已經(jīng)被注冊(cè)"
                })
            } else {
                // 第一個(gè)參數(shù)要展示的是 email 所以直接設(shè)置成 req.body.email
                // s 就是size   r 就是選擇圖片的格式  d 404會(huì)報(bào)錯(cuò) mm 會(huì)顯示一個(gè)頭像
                // 如果是在 gravatar 中已經(jīng)注冊(cè)過(guò)的用戶 就可以擁有屬于自己的頭像
                const avatar = gravatar.url(req.body.email, {s: '200', r: 'pg', d: 'mm'});
                
                const newUser = new User({    // newUser進(jìn)行一個(gè)存儲(chǔ)
                    name : req.body.name,
                    email : req.body.email,
                    avatar,  // 在es6中相同的名字寫一個(gè)就可以了
                    password : req.body.password  // 需要對(duì)當(dāng)前密碼進(jìn)行加密
                })
                // saltRounds這是一個(gè)加密模式 改為 10就可以了
             // myPlaintextPassword 這就表示 這個(gè)是要對(duì)誰(shuí)進(jìn)行加密
                bcrypt.genSalt(10, function(err, salt) {
                    bcrypt.hash(newUser.password, salt, function(err, hash) {
                        // 加密成功的話 就會(huì)返回返回一個(gè)加密的函數(shù)
                        if(err) throw err;
                        newUser.password = hash;
                        newUser.save()
                          .then( user => res.json(user) ); // 如果存儲(chǔ)成功就會(huì)返回一個(gè) user
                          .catch( err => console.log(err) );
                    });
                });
            }
        } )
    })
    
  • 需要對(duì)當(dāng)前密碼進(jìn)行加密

    • 然后需要安裝一個(gè) npm install bcrypt
    • 然后在什么地方需要安裝一個(gè)加密 就引入加密就可以了 代碼在上面的
  • 然后點(diǎn)擊 postman 進(jìn)行測(cè)試 輸入 賬戶密碼郵箱 等等 然后就可以進(jìn)行驗(yàn)證 就存入mongodb里面

  • 然后 mLab 里面進(jìn)行相對(duì)應(yīng)查看就可以了

全球公認(rèn)頭像gravatar

  • 安裝cnpm i gravatar -S

    然后在 users,js 中引入

    const gravatar = require('gravatar');
    // 然后具體代碼 在上面例子中會(huì)顯示。
    

搭建登錄接口

// users.js 頁(yè)面下的內(nèi)容

// $route POST api/users/login
// @desc  返回token   會(huì)用到 jwt passport 
// @access  public

router.post("/login",(req,res) => {
    const email = req.body.email;
    const password = req.body.password;
    // 查詢數(shù)據(jù)庫(kù)
    User.findOne({email})
        .then(user => {
        if(!user){
            return res.status(404).json({email:"用戶不存在"});
        }
        // 密碼匹配   
        // myPlaintextPassword就是獲取的密碼
        // hash 獲取到數(shù)據(jù)庫(kù)里面user下面的一個(gè) password 
        // bcrypt。compare(password,user.password,function(err,res){
        //     // res == true
        // })
        bcrypt。compare(password,user.password)
            .then(isMatch => {
            if(isMatch){
                // jwt.sign("規(guī)則","加密名字","過(guò)期時(shí)間","箭頭函數(shù)");
                const rule = {id:user.id,name:user.name};
                jwt.sign(rule,keys.secretOrKey,{expiresIn:3600},(err,token)=> {
                    if(err) throw err;
                    res.json({
                        success : true,
                        token : "gl " + token    // 這樣這里返回的就是 gl+規(guī)則的一個(gè)值啦
                    });
                });
                
                // res.json({msg:"success"}) // 這個(gè)地方之后會(huì)返回一個(gè) token
            }else{
                return res.status(400).json({password:"密碼錯(cuò)誤"}); 
            }
            // 然后在 postman 中測(cè)試的時(shí)候就可以進(jìn)行相對(duì)應(yīng)的測(cè)試
        })
    })
})

Node接口搭建 - 使用jwt實(shí)現(xiàn)token

  • 安裝第三方包 cnpm i jsonwebtoken -S

    const jwt = require('jsonwebtoken');
    // 然后具體代碼 在上面有寫入  在寫jwt 的 secretOrKey 的時(shí)候在keys.js中定義暴漏一下
    const keys = require('../../config/keys');
    
    // keys.js 內(nèi)容如下
    {
        secretOrKey : "secret"
    }
    

Node接口搭建 - 使用passport驗(yàn)證token

  • token

    相當(dāng)于是一個(gè)令牌 拿著令牌去請(qǐng)求對(duì)應(yīng)的數(shù)據(jù)庫(kù)的信息 如果沒有token 或者 token過(guò)期的就得不到數(shù)據(jù)了

    // user.js 頁(yè)面內(nèi)容
    
    // $route GET api/users/current           這里是假定用戶已經(jīng)拿到對(duì)應(yīng)的數(shù)據(jù)啦 然后是想要請(qǐng)求信息
    // @desc  return user 
    // @access  Private
    // router.get("/current","驗(yàn)證token",(req,res)={})
    router.get("/current",,(req,res)={
        res.json({msg : "success"});
    })
    
  • 安裝 cnpm i passport passport-jwt -S

  • 引入 passport 在server中引入

    // server.js
    const passport = require("passport");
    
    // passport 的初始化   一定要進(jìn)行初始化
    app.use(passport.initialize());
    // 引入文 passport單獨(dú)寫在一個(gè)文件夾中    (passport)這個(gè)是傳遞過(guò)去的一個(gè) passport 
    require("./config/passport")(passport);   
    
    // poassport.js 內(nèi)容如下:
    const JwtStrategy = require('passport-jwt').Strategy,
          ExtractJwt = require('passport-jwt').ExtractJwt;
    const mongoose = require("mongoose");  // 引入他的原因就是需要用到 user.js
    const User = mongoose.model("users");
    const keys = require('../config/keys');
    
    // opts 是當(dāng)前的配置信息
    const opts = {}
    opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
    opts.secretOrKey = 'keys.secretOrKey;
    

前后端連載的模塊 concurrently

  • 將多個(gè)終端啟動(dòng)的項(xiàng)目進(jìn)行綁定 然后一次性進(jìn)行啟動(dòng)構(gòu)建

  • cnpm install concurrently -S

  • 然后進(jìn)行相關(guān)的配置

    在根目錄下面的 package.json 來(lái)進(jìn)行配置

    // 前端構(gòu)建頁(yè)面的 package.json
    {
        "serve" : "vue-cli-service serve",
        "build" : "vue-cli-service build",
        "start" : "npm run serve" // 這里是將 serve 進(jìn)行啟動(dòng)使用的是 npm start 命令
    }
    // 后端構(gòu)建的package.json 里面進(jìn)行構(gòu)建
    { // 首先確定了 前端 已經(jīng)依賴了這里的模塊  格式就是 : 前端項(xiàng)目名稱-install
        "client-install" : "npm install --prefix client", // 當(dāng)啟動(dòng)的時(shí)候 首先安裝client的依賴模塊
        // npm start 就會(huì)啟動(dòng)當(dāng)前前端頁(yè)面的項(xiàng)目  然后 --prefix 會(huì)告知啟動(dòng)的路徑
        "client" : "npm start --prefix client",
        "start" : "node server.js",
        "server" : "nodemon server.js",
        // 接下來(lái)就是要啟動(dòng) 連載的項(xiàng)目  npm run client/server 就會(huì)啟動(dòng)前端/后端項(xiàng)目 接下來(lái)進(jìn)行綁定構(gòu)建
        "dev" : "concurrently \"npm run server\" \"npm run client\""
        // 然后就可以進(jìn)行 一次性啟動(dòng) 來(lái)啟動(dòng)前后端項(xiàng)目連載的過(guò)程了
    } 
    

路由守衛(wèi)

  • 只能訪問(wèn) 注冊(cè)和的登錄頁(yè)面其他的頁(yè)面都訪問(wèn)不了 這就是路由守衛(wèi)

    // router.js 下的內(nèi)容
    // 路由守衛(wèi)
    router.beforEach((to,form.next)=>{
        // 即使判斷 lg 中是否擁有 token 擁有的話 就是登錄狀態(tài) 
        const isLogin = localStorage.eleToken ? true : false;
        if(to.path == '/login' || to.path == '/register'){
            next();
        } else {
            isLogin ? next() : next('/login');
        }
    });
    
    // http.js 下的內(nèi)容
    // 請(qǐng)求攔截
    axios.interceptors.request.use(
        config => {
            // 加載動(dòng)畫
            startLoading();
            if(localStorage.eleToken) {
                // 設(shè)置統(tǒng)一的請(qǐng)求 header
                config.header.Authorization = localStorage.eleToken;
            }
            
            return config;
        }
    )
    
    // 響應(yīng)攔截
    // 看一下當(dāng)前的狀態(tài)碼是不是401 如果是401說(shuō)明token已經(jīng)失效了 然后將ls中的token刪除
    axios.interceptors.response.use(
        response => {
            // 結(jié)束加載動(dòng)畫
            endLoading();
            return response;
        },
        error => {
            // 錯(cuò)誤提醒
            endLoading();
            Message.error(error.response.data);
            
            // 獲取錯(cuò)誤狀態(tài)碼
            const { status } => error.response;
            if(status == 401){
                Message.err("token失效,請(qǐng)重新登錄~");
                // 清楚token
                localStorage.removeItem('eleToken');
                // 跳轉(zhuǎn)到登錄頁(yè)面
                router.push('/login');
            }
            
            return Promise.reject(error);
        }
    )
    

解析token數(shù)據(jù) 并且 存儲(chǔ)到 vuex 里面

  • 需要安裝一個(gè) 解析 token 的模塊 cnpm install jwt-decode -S

    import jwt_decode from 'jwt-decode';
    
    submitForm(formName){
        ...
        // 存儲(chǔ)到 ls
        localStorage.setItem('eleToken',token);
        
        // 解析 token
        const decoded = jwt_decode(token);
        console.log(decoded);
        
        ...
    }
    

    然后將解析的內(nèi)容進(jìn)行一個(gè)存儲(chǔ) 存儲(chǔ)到 vuex

    // store.js下的內(nèi)容
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    const types = {
        SET_AUTHENTICATED : "SET_AUTHENTICATED", //判斷是否認(rèn)證通過(guò)
        SET_USER : "SER_USER"
    }
    
    const state = {
        isAuthentivated : false,  // 是否授權(quán)
        user : {              // 會(huì)將信息保存到user這個(gè)狀態(tài)中去
             
        }
    }
    
    const getters = {
        
    }
    
    const mutations = {
        
    }
    
    const actions = {
        
    }
    
    export default new Vuex.Store({
        state,
        getters,
        mutations,
        actions
    })
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容