Node教程——API接口開發(MangoDB+Express)

git源碼

說明:源碼已經所有上傳到github,倉庫地址: https://github.com/BM-laoli/Node-api-Designhtml

模塊依賴關係圖

1、大綱

  • 大綱:
    關於架構,
    1. 首先咱們的有一個app.js這個就是根路由起點,用來最初的打入口
      它的功能有:
      1.1 引入模塊建立基礎的網站服務器,
      1.2 導入bodyPasser,過濾還有處理咱們的post請求
      1.3 導入數據庫鏈接
      1.4 把路由開放出去git

    2. 再來一個main.js它在個人route文件夾下,
      2.1 什麼需啊喲再這裏作二次攔截,再進行分配路由,
      2.2 引入兩個邏輯處理模塊,當請求發來的時候,若是不是login那麼咱們就須要驗證token,
      2.3 若是訪問的是login那麼咱們須要,發post數據,來到處理驗證,而後拿token,
      2.4 若是有token,那麼再來訪問2.2這裏的不是logi的其它路由路徑,的校驗就經過了,因而乎咱們就能分配各類接口了es6

    3. 詳細的講解輔助,工具代碼
      3.1 這裏有咱們在主線邏輯裏須要的一些工具
      3.2 中間件Middleware,裏面有兩個工具,一個是生成token的一個校驗token的
      3.3 在3.2中的功能 須要依賴model下的一個util下的jwt工具生成token生成的依據是兩個密鑰對
      3.4 咱們還有兩個工具,content 建立數據庫的連接,create初始化數據還有開發數據操做對象github

2、展現 接口 API文檔

1.1 登陸

請求地址 請求方式
/main/login POST
參數名稱 是否必選 參數說明
email 郵箱
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寫接口的最基礎的內容。能夠在這個內容上擴展更多的接口web

2、 app.js模塊的詳解

app.jsmongodb

//引入模塊,建立簡單服務器
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('服務器開啓');

3、 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: '登錄成功', });
}

4、 輔助工具(重點!!!)

  • 數據庫鏈接,設計還有初始化建立模塊
    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.jsexpress

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;

5、 最後咱們梳理一下,這些模塊之間的關係

其實這套接口下來,我比較菜雞,用了兩天的工做之餘的時間,因爲我沒怎麼接觸接口的設計,對於後臺的一些設計模式還有理念不是特別懂,走了不少彎路,以上的是我寫了三次筆記,長達2000多行子,反覆的修改,才成型,但願大佬高擡貴手指點迷津,也但願,這篇入門的文檔,能給你帶來收穫,接下里,我就用這裏的模型,開發更多的接口。敬請期待。json

  • 各個模塊的引用關係,用例圖

相關文章
相關標籤/搜索