上一篇文章中主要演示了HTML5表单发送HTTP请求时的数据处理。这篇文章将把关注点放在后端express应用上。接下来将解析部分express源码来了解expres是如何处理请求的。
代码仓库:https://github.com/jczzq/cool...
express(@4.16.3)
const express = require('express');
const app = express();
// app.use([path,] function [, function...])
app.use('/user/:id', (req, res, next) => {
return res.sendStatus(200);
});
这是我们的express应用代码,app.use
将挂载一个中间件,处理匹配/user/XXX
路径的所有请求,不管是POST或是GET请求。
- /user 不匹配
- /user?id=233 不匹配
- /user/123 匹配
这个中间件的处理函数是必传参数,处理函数有三个可用参数:
- req: 继承了http.IncomingMessage
- res: 继承了http.ServerResponse
- next: 将控制权交给下一个中间件,如果当前中间件没有终结请求,并且next没有被调用,那么请求将被挂起,后边定义的中间件将得不到被执行的机会。
HTTP请求消息在express中的体现
Node
起始行
之前说过的消息起始行三部分:
- 请求路径 req.url
- http版本 req.httpVersion
- http动作 req.method
三个属性都是继承自Node http API,另外express根据req.url补充完善了多个常用的属性,比如
- req.query:将原本链接上的urlencode编码的参数序列化成了json对象,并且可以通过req.query属性轻松访问。
查看序列化处理源码:https://github.com/expressjs/... - req.params:将原本链接上的/:XX部分处理并序列化成了json对象,可以通过req.params属性轻松访问。
查看源码:https://github.com/expressjs/...
请求头
express中查看原始请求头可以通过req.rawHeaders
或req.headers
获取
- req.rawHeaders 不是express提供的属性,而是继承自Node http.IncomingMessage类,键和值在同一个列表中。偶数位的是键,奇数位的是对应的值。头信息的名称不会被转换为小写,重复的也不会被合并。
- req.headers 头信息的名称与值的键值对。 头信息的名称为小写。原始头信息中的重复数据会按照特定规则进行处理:
curl http://localhost:3000/user/233
输出req.rawHeaders
输出req.headers
请求体
根据express文档描述req.body是唯一用于接收请求体的属性。我们发送请求并返回相关参数,现在我们分别发送application/x-www-form-urlencoded
,multipart/form-data
,text/plain
三个类型的请求体参数看看什么情况。
app.use('/user/:id', (req, res, next) => {
return res.json({
query: req.query,
params: req.params,
body: req.body
});
});
application/x-www-form-urlencoded
但实际上没有看到res.body属性的值。
multipart/form-data
multipart/form-data
呢?也没有
text/plain
text/plain
呢?还是没有。看来是没有找到正确的打开方式。
body-parser & multer
body-parser
express处理请求体需要使用专门的解析插件,官方推荐使用body-parser
和multer
,这两个都是用来处理请求体的,不同的是,
multer只处理'multipart/form-data',其余类型的都可以由body-parser处理。拆分开的原因是为了你的应用能更自由地搭配。鉴于web开发中post请求量大,消息体解析频繁,所以express@4.x之前一直都是内置body-parser作为解析器(事实上body-parser的作者TJ也正是express的作者)。
express源码 /lib/express.js
/**
* Expose middleware
*/
exports.json = bodyParser.json
exports.query = require('./middleware/query');
exports.static = require('serve-static');
exports.urlencoded = bodyParser.urlencoded
/**
* Replace removed middleware with an appropriate error message.
*/
;[
'bodyParser',
'compress',
'cookieSession',
'session',
'logger',
'cookieParser',
'favicon',
'responseTime',
'errorHandler',
'timeout',
'methodOverride',
'vhost',
'csrf',
'directory',
'limit',
'multipart',
'staticCache',
].forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});
最近express@4.x发布了一批新特性,同时也解除了内置的body-parser,只保留了更加常用的两个函数:json
和urlencoded
,你可以通过express全局对象访问这两个解析函数,你基本上再也不用单独引入body-parser了。
multer
var multer = require('multer');
app.use(multer()); // multipart/form-data
multer库是专门为了解决Form上传文件而生的,在body-parser为了遵循渐进式架构理念而放弃解析复杂的multipart/form-data
消息体时,multer应运而生,它使用场景不是很频繁但显然有时候缺它不可。
修改代码如下:
const path = require('path');
const express = require('express');
const app = express();
const multer = require('multer');
// 设置静态文件目录
app.use(express.static(path.resolve('./static')));
console.info('静态文件目录:', path.resolve('./static'));
// 首页
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, './index.html'));
});
app.use(express.json()); // for parsing application/json
app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
const upload = multer({ dest: 'uploads/' }); // for parsing multipart/form-data
app.use('/user/:id', upload.single('avatar'), (req, res, next) => {
return res.json({
query: req.query,
params: req.params,
file: req.file,
body: req.body
});
});
app.listen(3000, '0.0.0.0', () => {
console.log('启动服务器: http://localhost:3000');
});
选张图片提交
解析成功!
因为multer设置了{ dest: 'uploads/' }
,所以成功保存了图片到指定文件夹内。
参考链接
https://github.com/expressjs/...
https://www.nodeapp.cn/http.html
https://github.com/expressjs/...
http://www.expressjs.com.cn/4...
如有不足 欢迎指正
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。