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地址