git源碼
說明:源碼已經全部上傳到github,倉庫地址: https://github.com/BM-laoli/Node-api-Design
模塊依賴關系圖
一、大綱
- 大綱:
關於架構,-
首先我們的有一個app.js這個就是根路由起點,用來最初的打入口
它的功能有:
1.1 引入模塊創建基礎的網站服務器,
1.2 導入bodyPasser,過濾還有處理我們的post請求
1.3 導入數據庫連接
1.4 把路由開放出去 -
再來一個main.js它在我的route文件夾下,
2.1 什么需啊喲再這里做二次攔截,再進行分配路由,
2.2 引入兩個邏輯處理模塊,當請求發來的時候,如果不是login那么我們就需要驗證token,
2.3 如果訪問的是login那么我們需要,發post數據,來處處理驗證,然后拿token,
2.4 如果有token,那么再來訪問2.2這里的不是logi的其它路由路徑,的校驗就通過了,於是乎我們就能分配各種接口了 -
詳細的講解輔助,工具代碼
3.1 這里有我們在主線邏輯里需要的一些工具
3.2 中間件Middleware,里面有兩個工具,一個是生成token的一個校驗token的
3.3 在3.2中的功能 需要依賴model下的一個util下的jwt工具生成token生成的依據是兩個密鑰對
3.4 我們還有兩個工具,content 創建數據庫的鏈接,create初始化數據還有開發數據操作對象
-
二、展示 接口 API文檔
1.1 登錄
請求地址 | 請求方式 |
---|---|
/main/login | POST |
參數名稱 | 是否必選 | 參數說明 |
---|---|---|
是 | 郵箱 | |
password | 是 | 密碼 |
{
"status": 200,
"msg": "登陸成功",
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiNWU5MTIwMTViOWI0NmYzZmE4Y2MzMjUzIiwiZXhwIjoxNTg2OTUyMzk1LCJpYXQiOjE1ODY5NTA1OTV9.IsprCaQ_gZRh0BzS8SnAd0iJ27BOpOEb-ZGn0bTlwHVPTiYPK50wiEOL_0aAYINfNT_Mfvb726l3CpiHG9lsJ45m4eqhPeJz9TbAeQj8-ST3CAkYLrD0fhgRG9YiQ5kjVpygdR8NZEWEUV7ux-moyYe7wCoVzN9mbvAkFF3IYG0"
}
1.2 拿着token進行測試
請求地址 | 請求方式 |
---|---|
/main/text | get |
參數名稱 | 是否必選 | 參數說明 |
---|---|---|
token | 是 | 需要附上你的token。在請求頭中 |
無 | 無 | 該接口不需要傳遞參數 |
{
"status": 200,
"msg": "登陸成功"
}
注意:以上就是Node寫接口的最基礎的內容。可以在這個內容上擴展更多的接口
二、 app.js模塊的詳解
app.js
//引入模塊,創建簡單服務器
const express = require('express');
//引入路徑處理模塊
const path = require('path');
//引入注意使用第三方模塊處理post
const bodyPaser = require('body-parser')
// 引入數據庫連接 不需要返回值
require('./model/content')
//創建服務器
const app = express();
/*//初始化數據庫,注意reque的時候 會自動執行引入的js文件
require('./model/create')
*/
//前往小心這個要放在所有的use前面,解析我們的post請求數據
app.use(bodyPaser.urlencoded({ extended: false }));
//處理靜態資源路徑
const DataPath = path.join(__dirname, 'public');
//這個我們后面是有用的,用來操作媒體數據,最重要的就是這個路徑還有這個靜態資源對象
const StaticUtils = express.static(path.join(__dirname, 'public'));
//拿到路由操作對象
const main = require('./route/mian/main');
//開放接口路徑
//攔截請求開始匹配路由
app.use('/dataPath', (req, res) => {
res.status(200).send(JSON.stringify({ 'dataPath': DataPath }))
})
app.use(StaticUtils);
app.use('/main', main)
//監聽端口
app.listen(3000)
console.log('服務器開啟');
三、 main.js二次路由攔截模塊
main.js
const express = require('express')
//業務邏輯
const guard = require('../../Middleware/loginGuard')
const loginPash = require('../../Middleware/loginPash')
//創建路由對象
const admin = express.Router()
//驗證token
admin.use(loginPash)
//登錄路由處理
admin.post('/login', guard)
//首先要驗證,然后才是放行到對應的路由接口里面取
admin.get('/text', require('./API/home/index'))
module.exports = admin;
- 攜帶的一個簡單的測試模塊(后續可以仿照這樣的模式,寫更多的API接口功能模塊)
home/index.js
module.exports = async(req, res) => {
res.send({ status: 200, msg: '登陸成功', });
}
四、 輔助工具(重點!!!)
- 數據庫連接,設計還有初始化創建模塊
model/content.js && model/create.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/blog')
.then(() => {
console.log('數據庫連接成功');
})
.catch((erro) => {
console.log(erro);
})
const mongoose = require('mongoose');
const bcrypt = require('bcrypt')
/*使用MongDB數據庫,設計數據第一步(代碼角度分析)
1.設定規則,Schema構造器,Schema的構造函數就是規則,注意規則是一系列對象
2.創建數據
*/
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
min: 2,
max: 10
},
email: {
type: String,
//注意 我們的郵箱憑據是用戶登錄的令牌,我們需要指定他為唯一的
unique: true, //這個時候,在插入的時候如果有重復的就給你抱一個錯誤
},
password: {
type: String,
required: true,
},
role: { //需要說明一下,這個地方角色,我們硬性規定,超級管理員是admin普通用戶是normal,為什么不用01?因為這里string了
type: String,
required: true
},
state: {
//我們使用O1狀態來設計這個數據字段,默認值是0。0是啟用狀態
type: Number,
default: 0
}
})
//使用規則創建集合,
//一定要注意,我們的User就是代表了我目前最user數據集合,后期的增刪改查我們都需要用到這個東西,所有我們暴露出去給路由業務使用
const User = mongoose.model('User', userSchema)
//我們再來復習一下,如何用同步的方式獲取異步的api結果?使用async 還有awit就可以
async function createUser() {
const salt = await bcrypt.genSalt(10)
const pass = await bcrypt.hash('123456', salt)
const user = await User.create({
username: 'lli',
email: '18376621755@163.com',
password: pass,
role: 'admin',
state: 0,
})
}
// createUser()
/* // 初始化用戶,注意我們的create返回的是一個promies
User.create({
username: 'bmlaoli',
email: '861795660@qq.com',
password: '123456',
role: 'admin',
state: 0,
})
.then(() => {
console.log('用戶創建成功');
})
.catch((error) => {
console.log('用戶創建失敗');
})*/
//注意啊,es6中如果鍵值對的名字是一樣的就可以省略值。由於我們后期還會做更多的數據集合,於是乎我這里需要暴露一個對象出去
module.exports = {
User
}
- 另一個重要的工具模塊,用來創建token 根據就是文件夾下的兩個密鑰對文件
jwt.js
/*
*描述:以下是jwt工具,生成用於訪問驗證的token
*/
// 引入模塊依賴
const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken');
// 創建 token 類
class Jwt {
constructor(data) {
this.data = data;
}
//生成token
generateToken() {
let data = this.data;
let created = Math.floor(Date.now() / 1000);
let cert = fs.readFileSync(path.join(__dirname, '../../pem/private_key.pem')); //私鑰 可以自己生成,注意這里要使用 密鑰對,請求百度下載,兩對密鑰對
let token = jwt.sign({
data,
exp: created + 60 * 30,
}, cert, { algorithm: 'RS256' });
return token;
}
// 校驗token
verifyToken() {
let token = this.data;
let cert = fs.readFileSync(path.join(__dirname, '../../pem/public_key.pem')); //公鑰 可以自己生成
let res;
try {
let result = jwt.verify(token, cert, { algorithms: ['RS256'] }) || {};
let { exp = 0 } = result, current = Math.floor(Date.now() / 1000);
if (current <= exp) {
res = result.data || {};
}
} catch (e) {
res = 'err';
}
return res;
}
}
module.exports = Jwt;
- 接下里是兩個具體的token校驗功能模塊
我把它們都放到了middleware文件夾下
loginGuard.js && loginPash.js
const JwtUtil = require('../model/util/jwt')
const { User } = require('../model/create')
const bcrypt = require('bcrypt')
const guard = async(req, res, next) => {
//注意使用第三方模塊處理post
//進圖具體的業務邏輯,解構出來我們需要的東西
const { email, password, _id } = req.body; //注意啊,由於我們的中間件處理的請求於是乎我們的req身上就有這個處理的所有數據了,這個之前有說過
console.log(req.body);
if (email.trim().length == 0 || password.trim().length == 0) {
res.status(400).send(
JSON.stringify({ message: '郵箱或密碼錯誤' })
) //注意send自動把狀態碼設置成了200,所以你需要改一下
return
}
//如果用戶存在就先找到這個用戶額信息,注意這里的這個異步await
let user = await User.findOne({ email });
//這里的user就是指向當前查詢出來的數據文檔對象
if (user) {
//比對操作,第一個參數是一個明文密碼,第二個參數我們查詢出來的加密密碼 ,方法返回一個Boolean值,對比成功就是true,異步api可以直接加await
const isValid = await bcrypt.compare(password, user.password)
if (isValid) {
//用戶校驗成功,添加tooken
// 登陸成功,添加token驗證
let _id = user._id.toString();
// 將用戶id傳入並生成token
let jwt = new JwtUtil(_id);
let token = jwt.generateToken();
// 將 token 返回給客戶端
res.send({ status: 200, msg: '登陸成功', token: token });
//校驗成功就
next()
} else {
res.status(400).send(
JSON.stringify({ message: '郵箱或密碼錯誤' })
)
}
} else {
res.status(400).send(
JSON.stringify({ message: '郵箱或密碼錯誤' })
)
}
}
module.exports = guard
loginPash.js
const JwtUtil = require('../model/util/jwt')
//驗證token
const loginPash = function(req, res, next) {
// 我這里知識把登陸和注冊請求去掉了,其他的多有請求都需要進行token校驗
if (req.url != '/login?') {
let token = req.headers.token;
let jwt = new JwtUtil(token);
let result = jwt.verifyToken();
// 如果考驗通過就next,否則就返回登陸信息不正確
if (result == 'err') {
console.log(result);
console.log(req.url);
res.send({ status: 403, msg: '登錄已過期,請重新登錄' });
// res.render('login.html');
} else {
next();
}
} else {
next();
}
};
module.exports = loginPash;
五、 最后我們梳理一下,這些模塊之間的關系
其實這套接口下來,我比較菜雞,用了兩天的工作之余的時間,由於我沒怎么接觸接口的設計,對於后台的一些設計模式還有理念不是特別懂,走了很多彎路,以上的是我寫了三次筆記,長達2000多行子,反復的修改,才成型,希望大佬高抬貴手指點迷津,也希望,這篇入門的文檔,能給你帶來收獲,接下里,我就用這里的模型,開發更多的接口。敬請期待。
- 各個模塊的引用關系,用例圖