通过 Node express服务端程序深入了解HTTP请求(二)

上一篇文章中主要演示了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 不匹配
    通过 Node express服务端程序深入了解HTTP请求(二)
  • /user?id=233 不匹配
    通过 Node express服务端程序深入了解HTTP请求(二)
  • /user/123 匹配
    通过 Node express服务端程序深入了解HTTP请求(二)
    通过 Node express服务端程序深入了解HTTP请求(二)

这个中间件的处理函数是必传参数,处理函数有三个可用参数:

  • req: 继承了http.IncomingMessage
  • res: 继承了http.ServerResponse
  • next: 将控制权交给下一个中间件,如果当前中间件没有终结请求,并且next没有被调用,那么请求将被挂起,后边定义的中间件将得不到被执行的机会。

HTTP请求消息在express中的体现

Node

起始行

之前说过的消息起始行三部分:

  • 请求路径 req.url
  • http版本 req.httpVersion
  • http动作 req.method

通过 Node express服务端程序深入了解HTTP请求(二)

三个属性都是继承自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.rawHeadersreq.headers获取

  • req.rawHeaders 不是express提供的属性,而是继承自Node http.IncomingMessage类,键和值在同一个列表中。偶数位的是键,奇数位的是对应的值。头信息的名称不会被转换为小写,重复的也不会被合并。
  • req.headers 头信息的名称与值的键值对。 头信息的名称为小写。原始头信息中的重复数据会按照特定规则进行处理:

curl http://localhost:3000/user/233
通过 Node express服务端程序深入了解HTTP请求(二)

输出req.rawHeaders
通过 Node express服务端程序深入了解HTTP请求(二)

输出req.headers
通过 Node express服务端程序深入了解HTTP请求(二)

请求体

根据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

通过 Node express服务端程序深入了解HTTP请求(二)
通过 Node express服务端程序深入了解HTTP请求(二)
但实际上没有看到res.body属性的值。

multipart/form-data

通过 Node express服务端程序深入了解HTTP请求(二)

multipart/form-data呢?也没有

text/plain

通过 Node express服务端程序深入了解HTTP请求(二)

text/plain呢?还是没有。看来是没有找到正确的打开方式。

body-parser & multer

body-parser

express处理请求体需要使用专门的解析插件,官方推荐使用body-parsermulter,这两个都是用来处理请求体的,不同的是,
multer只处理'multipart/form-data',其余类型的都可以由body-parser处理。拆分开的原因是为了你的应用能更自由地搭配。鉴于web开发中post请求量大,消息体解析频繁,所以[email protected]之前一直都是内置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
  });
});

最近[email protected]发布了一批新特性,同时也解除了内置的body-parser,只保留了更加常用的两个函数:jsonurlencoded,你可以通过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');
});

选张图片提交
通过 Node express服务端程序深入了解HTTP请求(二)
通过 Node express服务端程序深入了解HTTP请求(二)

解析成功!

通过 Node express服务端程序深入了解HTTP请求(二)

因为multer设置了{ dest: 'uploads/' },所以成功保存了图片到指定文件夹内。

参考链接

https://github.com/expressjs/...
https://www.nodeapp.cn/http.html
https://github.com/expressjs/...
http://www.expressjs.com.cn/4...

如有不足 欢迎指正

相关推荐