五、Node+Mongoose+Express搭建一个属于自己的后台服务——封装(db、接口、验证)

1、简介

上一篇讲到了简单的接口开发,但现实中使用会对接口模块化然后进行统一的设置,拦截,验证。返回会进行封装,设置。对于接口的报错也会进行统一处理

2、接口模块化

接口模块的目录结构,handle根目录,model各个流程或页面的接口集合,具体看自己如何划分,index统一导出入口

接口的意义就是读表写表,那写接口前需要先连接数据库的表,schema根目录


接下来正式开发接口

1)、在schema根目录下创建hotal.js,在js文件中定义schema集合,举个栗子,获取推荐酒店列表


/**
 * 酒店推荐
 * recommend_hotal
 */

const RecommendHotalSchema = new Schema({
  img: String,
  hotelName: String,
  price: String,
  deletePrice: String,
  starIcon: String,
  url: String,
  isAdHotel: String,
  adTraceId: String,
  scenario: String,
  comment: Object,
  cityId: String,
})
/**
 * 连接到数据库
 * 注意点:recommend_hotals为数据库表的名称,如果名称不带s,数据库的表名会自动带上
 * 解决方案:如果实在不需要s,可以在model中,加上第三个参数,表名。
 */
const RecommendHotal = mongoose.model("recommend_hotals", RecommendHotalSchema);

2),在handle根目录下的model文件夹下创建hotal.js接口文件,引入schema集合

// 引入schema集合
const RecommendHotal = require('../../schemas/hotal').RecommendHotal;

// 导出接口
module.exports = {
     /**
     * 获取热门推荐酒店
     * @param {cityId} req 
     * @param {*} res 
     */
    async getRecommendHotal(req, res) {
        const body = await Header.getParams(req, res, ['cityId'])
        let data = {
            cityId: body.cityId
        }
        RecommendHotal.find(data).then(hotal => {
            jsonParse.sendResult(res, 200, hotal, '获取成功')
        })
    },
}

将model下的所有文件,统一通过index.js曝光出去

// 接口集合
const hotal= require('./model/hotal')

module.exports = {
 // 携程
    ...hotal,
}

3)、handle文件内曝光出来的方法如何调用呢?接下来就需要在server.js内添加接口的统一拦截了

// 引入 接口文件集合
const requestHandler = require('./handle')

//拦截所有api接口设置头部信息(不能放底部,放在app.listen前)
app.all('*', function (req, res, next) {
    //跨域
    res.header('Access-Control-Allow-Origin', '*');
    res.header("Access-Control-Allow-Headers", "Authorization, Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name");
    // //设置前端的这些ajax请求方法'GET,POST,PUT,HEAD,DELETE,OPTIONS',都有权限调接口
    res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,HEAD,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Credentials', true);
    // console.log(req.url,'前端传进来的参数为===:',req.method == 'GET'?req.query:req.body)
    // console.log(req.url)
    if ('OPTIONS' == req.method) {
        res.sendStatus(200)
    } else {
        // 线上需要进行nginx反向代理,截取代理,获取接口名称
        let requestName = req.url.replace('/api', '')
        // 通过接口名称映射到handle内的方法上
        let route = routeMap[requestName] || {}
        // 通过获取到的方法名在handle内调用接口
        let handler = requestHandler[route.handler]
        // 判断是不是方法,或者说接口是否存在,存在的话,是不是函数
        if (typeof handler === 'function') {
            // 是否需要进行用户验证
            if (route.needVerify) {
                // 调用用户验证方法
                requestHandler.verifyLogin(req, res, handler)
             } else {
                // 调用接口
                handler(req, res)
             }
        } else {
            // 不是方法直接返回
            requestHandler['noHandler'](req, res)
        }
        return
    }
});

其实通过上面的代码可以看到还有一些没有说到,却使用了,比如routeMap,verifyLogin,noHandler,下面对这三部分做个讲解

1,routeMap

这个文件的主要作用是进行接口的映射,还有一些接口的配置,比如是否需要验证,这个文件目录与接口目录一样

hotal.js

module.exports = {
    '/getRecommendHotal': {
        handler: 'getRecommendHotal',
        needVerify: false
    },
}

index.js

const hotalRoute = require("./views/hotal")

const routeMap = {
    ...hotalRoute
}

module.exports = routeMap

这样一个接口与方法的映射便创建完成了

2、verifyLogin

这个一般做后台管理系统是需要进行接口的验证,防止盗取数据,在handle的index.js文件中可以加入verifyLogin方法和noHandler方法,在配置文件中取出secret秘钥,使用jwt尽行验证,具体使用方法可以在npm官网搜索

const jwt = require('jsonwebtoken');
const jsonParse = require('../lib/jsonParse')
const secret = require('../config/keys')
// 接口集合
const hotal= require('./model/hotal')
module.exports = {
    // 携程
    ...hotal,
    // 接口不存在
    noHandler: (request, response) => {
        jsonParse.sendResult(response, 404, '接口不存在')
    },
    // 验证Token
    verifyLogin: (request, response, handler) => {
        if (request.headers['authorization']) {
            const token = request.headers['authorization'].replace('Bearer ', '');
            jwt.verify(token, secret.secretOrKey, function (err, data) {
                if (err) {
                    if (err.name == 'TokenExpiredError') {
                        jsonParse.sendResult(response, '-101')
                    } else if (err.name == 'JsonWebTokenError') {
                        jsonParse.sendResult(response, '-102')
                    }
                } else {
                    const decodeResult = jwt.decode(token)
                    let userName = decodeResult.userName
                    handler(request, response, userName)
                }
            })
        } else {
            jsonParse.sendResult(response, '-103')
        }
    }
}

3、noHandler

当接口未定义或定义错误,导致接口找不到时的处理方法

4)、以上都是方法不存在,或存在不报错的情况,那如果接口存在但报错了,如何统一处理呢?

node自带process.on()回调函数,可以放任何地方,如果要返回给前台,我们可以在统一拦截时将response定义变量接收,然后将错误抛出,也可以自己存日志

process.on('unhandledRejection', error => {
    console.log('我帮你处理了', error.message);
    jsonParse.sendResult(response, -2002, error.message)
})

3、结尾

代码中还涉及到一些方法的封装,比如jsonParse.sendResult,具体可以在码云上查看源码。

后台node地址

myServer: NodeJs + Express + Mongoose

前台vue地址

myVite: nodejs前台项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值