Vue-Cli3 + Node Project
項(xiàng)目展示以及技術(shù)棧
NodeJS構(gòu)建后端接口 VueCli3.0構(gòu)建前端頁(yè)面
- 構(gòu)建接口文檔:Node + express + jwt
- 構(gòu)建前端頁(yè)面:VueCli3.0 + Elemenet-ui
- 數(shù)據(jù)請(qǐng)求及攔截 : Axios + Mlab + MongoDB
- 分頁(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就可以了-
然后是 為了 不一直重啟 所以就 安裝 nodemon
cnpm 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
- 然后選擇 區(qū)域 美國(guó) US East 然后設(shè)置名字 點(diǎn)擊
進(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è)加密 就引入加密就可以了 代碼在上面的
- 然后需要安裝一個(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 -Sconst 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 -Simport 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 })