版权声明:此文首发于我的个人站Keyon Y,转载请注明出处。

项目地址:https://github.com/KeyonY/NodeMiddle

express的逻辑处理分为两部分:转发后端接口中间件

转发后端接口

后端提供的接口分为两类:

  • 渲染页面使用的数据接口
  • 前端部分发送ajax请求的请求接口

数据接口

就是url的链接所能访问的页面。
先使用router.get()注册路由,路由内先通过axios访问后端获取页面数据response,通过 res.render()返回一个自定义的对象,将response作为对象的属性传递到pug模板页面中,在pug页面中便可以随意使用response。

参考github项目中 config/routes/default.js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 首页
router.get('/', addUser, (req, res, next) => {
axios.all([
axios.get('/Api/Carous'),
axios.get('/Api/Cars/Top10', {params: {page: req.query.page || 1}}),
])
.then(axios.spread(function (res1, res2){
config.throwError(next, res1, res2);
var page = req.query.page || 1;
res.render('Default/index', {
title: config.title('首页'),
keywords: config.keywords,
description: config.description,
menuNav: 0,
carList: res1.data.Data,
top10: res2.data.Data.slice((page-1)*3,page*3)
});
})).catch(e => {
config.renderError(req, res, e);
})
});

请求接口

是前端发送ajax请求的接口。
与数据接口的区别就是,中间层只做两件事:

  • 使用axios,转发前端的请求给后端
  • 使用res.send(),转发后端的响应给前端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// get请求
router.get('/User/Role', (req, res, next) => {
axios.get(config.origin + '/Api/User/Role', config.axiosHeaders(req, {
params: {role: req.query.role}
}))
.then(res1 => {
res.send(res1.data);
}).catch(e => {
config.sendError(res, e);
})
})

// post请求
router.post('/User/SendRequest', (req, res, next) => {
axios.post(config.origin + '/Api/User/SendRequest', {
userID: req.body.userID || null,
requestID: JSON.parse(req.body.requestID) || null
}, config.axiosHeaders(req))
.then((res2) => {
res.send(res2.data);
}).catch((e) => {
config.sendError(res, e);
})
});

post请求无法直接读取请求体,需要安装body-parser依赖

npm i –save body-parser

并在app.js挂载这个依赖

1
app.use(bodyParser.urlencoded({extended: false}));

获取前端请求中的参数

分为三种情况:

  • 获取带有参数的路由中的参数

    1
    2
    3
    4
    5
    6
    router.get('/Cars/:id', (req, res, next) => {
    axios.get(config.origin + '/Api/Cars', {
    params: {role: req.params.id} // req.params.id获取url中的参数
    }))
    ...
    })
  • 获取get请求的参数

    1
    2
    3
    4
    5
    6
    7
    // 例如这样的请求 /Cars/Search?q=tobi
    router.get('/Cars/Search', (req, res, next) => {
    axios.get(config.origin + '/Api/Cars/Search', {
    params: {car: req.query.q} // req.query.q获取参数
    }))
    ...
    })
  • 获取post请求的参数

    1
    2
    3
    4
    5
    6
    router.post('/Cars/Search', (req, res, next) => {
    axios.post(config.origin + '/Api/Cars/Search', {
    car: req.body.name // req.body.name获取请求体中的参数
    }))
    ...
    })

post请求转发数组对象

express post请求,获取客户端请求中的数组时,若是直接post一个数组,则express无法获取数组,需要在客户端对数组进行序列化,在中间层反序列化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 客户端
$.ajax({
url: '/Api/Mas/SendInfo',
type: 'POST',
data: {userID: userId, requestID: JSON.stringify(selected)}, // 序列化
success: function (res) {
log(res);
if(res.Status == 0){
$thisModal.hide();
$('#modal_cds').show();
}
}
})

// 中间层
axios.post(config.origin + '/Api/Mas/SendInfo', {
userID: req.body.userID || null,
requestID: JSON.parse(req.body.requestID) || null // 反序列化
}, config.axiosHeaders(req))

中间层不要传递有可能不存在的属性

千万不要在中间层传递有可能不存在的property!
千万不要在中间层传递有可能不存在的property!
千万不要在中间层传递有可能不存在的property!
重要的事情说三遍,不然出现下面的bug 都不知道在哪里找。

(node:20352) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property ‘data’ of undefined

中间件

Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。

中间件(Middleware) 是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。

中间件的功能包括:

  • 执行任何代码。
  • 修改请求和响应对象。
  • 终结请求-响应循环。
  • 调用堆栈中的下一个中间件。

如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。

Express 应用可使用如下几种中间件:

  • 应用级中间件
  • 路由级中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件

使用可选择挂载路径,可在应用级别或路由级别装载中间件。另外,你还可以同时装载一系列中间件函数,从而在一个挂载点上创建一个子中间件栈。

使用路由级中间件处理request对象

1
2
3
4
5
var addUser = require('../../middleware/addUser');
...
router.get('/Car/List', addUser, (req, res, next) => {
...
})

addUser即中间件,是一个方法,接受路由中的req,res,next三个参数,必须以next();结束代码,这样将函数指针从addUser,交给(req, res, next) => { …}。

使用中间件,可以获取请求头中的cookies,以验证用户登录信息
获取cookie的内容,需要安装cookie-parser依赖

npm i –save cookie-parser

在app.js中,挂载这个依赖就可以使用了。

1
app.use(cookieParser());

错误处理中间件-Error Handle

注意Error Handle的挂载的顺序,一般挂载到app.use()下,且放在最后。
请参考本系列博文的第二篇Node中间层实践(二)——搭建项目框架中app.js的介绍,或查看github项目代码的app.js。




欢迎继续关注本系列博文的其他精彩文章
Node中间层实践(一)——基于NodeJS的全栈式开发
Node中间层实践(二)——搭建项目框架
Node中间层实践(三)——webpack配置
Node中间层实践(四)——模板引擎pug
Node中间层实践(五)——express-中间层的逻辑处理