經過 Node express服務端程序深刻了解HTTP請求(二)

上一篇文章中主要演示了HTML5表單發送HTTP請求時的數據處理。這篇文章將把關注點放在後端express應用上。接下來將解析部分express源碼來了解expres是如何處理請求的。html

代碼倉庫:https://github.com/jczzq/cool...node

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請求。git

  • /user 不匹配
    clipboard.png
  • /user?id=233 不匹配
    clipboard.png
  • /user/123 匹配
    clipboard.png
    clipboard.png

這個中間件的處理函數是必傳參數,處理函數有三個可用參數:github

  • req: 繼承了http.IncomingMessage
  • res: 繼承了http.ServerResponse
  • next: 將控制權交給下一個中間件,若是當前中間件沒有終結請求,而且next沒有被調用,那麼請求將被掛起,後邊定義的中間件將得不到被執行的機會。

HTTP請求消息在express中的體現

Nodeweb

起始行

以前說過的消息起始行三部分:express

  • 請求路徑 req.url
  • http版本 req.httpVersion
  • http動做 req.method

clipboard.png

三個屬性都是繼承自Node http API,另外express根據req.url補充完善了多個經常使用的屬性,好比json

  • req.query:將本來連接上的urlencode編碼的參數序列化成了json對象,而且能夠經過req.query屬性輕鬆訪問。
    查看序列化處理源碼:https://github.com/expressjs/...
  • req.params:將本來連接上的/:XX部分處理並序列化成了json對象,能夠經過req.params屬性輕鬆訪問。
    查看源碼:https://github.com/expressjs/...

請求頭

express中查看原始請求頭能夠經過req.rawHeadersreq.headers獲取segmentfault

  • req.rawHeaders 不是express提供的屬性,而是繼承自Node http.IncomingMessage類,鍵和值在同一個列表中。偶數位的是鍵,奇數位的是對應的值。頭信息的名稱不會被轉換爲小寫,重複的也不會被合併。
  • req.headers 頭信息的名稱與值的鍵值對。 頭信息的名稱爲小寫。原始頭信息中的重複數據會按照特定規則進行處理:

curl http://localhost:3000/user/233
clipboard.png後端

輸出req.rawHeaders
clipboard.pngapi

輸出req.headers
clipboard.png

請求體

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

clipboard.png
clipboard.png
但實際上沒有看到res.body屬性的值。

multipart/form-data

clipboard.png

multipart/form-data呢?也沒有

text/plain

clipboard.png

text/plain呢?仍是沒有。看來是沒有找到正確的打開方式。

body-parser & multer

body-parser

express處理請求體須要使用專門的解析插件,官方推薦使用body-parsermulter,這兩個都是用來處理請求體的,不一樣的是,
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,只保留了更加經常使用的兩個函數: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');
});

選張圖片提交
clipboard.png
clipboard.png

解析成功!

clipboard.png

由於multer設置了{ dest: 'uploads/' },因此成功保存了圖片到指定文件夾內。

參考連接

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

若有不足 歡迎指正

相關文章
相關標籤/搜索