1. 什么是 express.urlencoded

Express.js 中的 express.urlencoded() 中间件是另一个内置函数,它在处理传入恳求中起着至关重要的作用。这个中间件专门设计用来解析内容类型为 application/x-www-form-urlencoded 的传入恳求体。这种内容类型一般用于 HTML 表单。本文对其原理和功用进行解释,并基于此手写一个简单的express.urlencoded中间件。

express.urlencoded() 的原理

  1. 意图

    • express.urlencoded() 的首要意图是解析传入恳求体的数据,这种数据格局是网页浏览器在运用 POST 办法从表单发送数据时一般运用的格局。
  2. 内容类型

    • 它专门处理 application/x-www-form-urlencoded 内容类型。这种格局是 HTML 表单提交中的标准,表单数据被编码为键值对。

功用

  1. 解析表单数据

    • 当客户端从表单提交数据时,数据被发送到服务器作为 URL 编码的字符串(字符以 URL 转义代码编码)。
    • express.urlencoded() 中间件将这些 URL 编码的数据解析成 JavaScript 目标。
  2. 附加到恳求目标

    • 解析后,中间件将成果目标附加到 req.body 属性上,类似于 express.json()。这使得表单数据在路由处理程序或后续中间件中易于拜访。
  3. 装备选项

    • extended:这个选项装备中间件运用 querystring 库(当为 false 时)或 qs 库(当为 true 时)进行解析。qs 库允许创立更丰富的目标,例如数组和嵌套目标。
    • limit:设置恳求体的最大巨细,供给对允许的数据量的控制。
  4. 常见用处

    • 常用于服务器需求承受来自 HTML 表单的提交数据的场景。
    • 在处理提交表单数据的 POST 恳求时尤为重要。

示例用法

const express = require('express');
const app = express();
// 激活 express.urlencoded 中间件
app.use(express.urlencoded({ extended: true }));
app.post('/form-submit', (req, res) => {
    console.log(req.body); // 客户端的表单数据
    // ...其他路由逻辑
});
app.listen(3000, () => console.log('服务器运行在 3000 端口'));

在这个示例中,任何对 /form-submit 的 POST 恳求,假如发送来自 HTML 表单(内容类型为 application/x-www-form-urlencoded)的数据,其体将被解析为通过 req.body 拜访的 JavaScript 目标。

定论

express.urlencoded() 是处理 Express.js 运用程序中表单提交的必需中间件。它解析 URL 编码的表单数据的能力使其成为网页运用程序中常见的表单处理需求不可或缺的部分。就像 express.json() 相同,它是 Express.js 中间件生态系统的要害组成部分,促进了客户端提交数据的简单高效处理。

2. DIY 完成 express.urlencoded

完成 express.urlencoded() 中间件的根本版别触及解析恳求体中的 URL 编码数据。这种类型的数据一般由 HTML 表单发送。创立这样的中间件的根本过程包括:

  1. 查看内容类型:保证恳求的 Content-Type 是 application/x-www-form-urlencoded
  2. 读取和解析恳求体:URL 编码数据作为恳求体中的字符串发送。这个字符串需求被解析成一个 JavaScript 目标。
  3. 将解析后的数据附加到 req.body:解析后,将成果目标附加到 req.body 属性上,以便在后续的中间件或路由处理程序中轻松拜访。

以下是带有相应代码的分步攻略:

过程 1:设置根本中间件结构

界说中间件函数的结构。它应该具有三个参数:reqresnext

function customUrlEncodedParser(req, res, next) {
    // 中间件逻辑将在此处编写
}

过程 2:查看内容类型

仅在内容类型为 application/x-www-form-urlencoded 时持续解析。

function customUrlEncodedParser(req, res, next) {
    if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
        // 持续解析
    } else {
        next(); // 假如不是 URL 编码,则跳过此中间件
    }
}

过程 3:读取和解析恳求体

运用流读取恳求体。URL 编码的数据以字符串方式呈现,咱们需求将其解析成键值对。

function customUrlEncodedParser(req, res, next) {
    if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
        let body = '';
        req.on('data', chunk => {
            body += chunk.toString(); // 将 Buffer 转换为字符串
        });
        req.on('end', () => {
            req.body = parseUrlEncoded(body);
            next();
        });
    } else {
        next();
    }
}
function parseUrlEncoded(str) {
    const pairs = str.split('&');
    return pairs.reduce((acc, pair) => {
        const [key, value] = pair.split('=');
        acc[decodeURIComponent(key)] = decodeURIComponent(value);
        return acc;
    }, {});
}

过程 4:在 Express 运用中运用中间件

就像运用 express.urlencoded() 相同,在 Express 运用中运用这个中间件。

const express = require('express');
const app = express();
app.use(customUrlEncodedParser);
app.post('/form-submit', (req, res) => {
    console.log(req.body); // 解析后的表单数据
    res.send('已收到表单数据');
});
app.listen(3000, () => console.log('服务器运行在 3000 端口'));

在这个设置中,任何对 /form-submit 的 POST 恳求,假如带有 URL 编码的数据(来自 HTML 表单),将被解析为通过 req.body 拜访的 JavaScript 目标。

留意

这个完成是一个根本版别,用于演示。实践运用场景可能需求处理更杂乱的数据结构,解码嵌套目标或处理数组。实践的 express.urlencoded() 中间件更加杂乱,能够处理各种边缘情况和装备,使其成为出产环境的更佳选择。

3. 扩展以完成选项装备

express.urlencoded({ extended: true }) 中的 { extended: true } 选项是一个重要的装备设置,它决议了怎么解析 URL 编码的数据。具体来说,它告诉中间件运用哪个解析库:

  • extended 设置为 true 时,中间件运用 qs 库进行解析。这个库允许将丰富的目标和数组编码成 URL 编码格局,意味着它可以处理嵌套目标。
  • extended 设置为 false 时,中间件运用 querystring 库,它不支持嵌套目标。

要完成这个功用的根本版别,您可以编写一个模仿这种行为的自界说解析函数。以下是怎么做到这一点:

过程 1:扩展解析函数

首要,界说一个基于 extended 选项的解析函数。为了简单起见,咱们将完成一个根本的办法来解析 extended 为 true 时的嵌套目标。完好的完成将需求一个更强大的解析算法,或直接运用 qs 库。

function parseUrlEncoded(str, extended) {
    if (!extended) {
        // 简单解析(不处理嵌套目标)
        return str.split('&').reduce((acc, pair) => {
            const [key, value] = pair.split('=');
            acc[decodeURIComponent(key)] = decodeURIComponent(value);
            return acc;
        }, {});
    } else {
        // 扩展解析的根本完成(处理嵌套目标)
        // 留意:这仅用于演示。完好的完成将更杂乱。
        return str.split('&').reduce((acc, pair) => {
            const [key, value] = pair.split('=');
            const path = key.split('[').map(k => k.replace(/]$/, ''));
            let current = acc;
            for (let i = 0; i < path.length - 1; i++) {
                if (!current[path[i]]) current[path[i]] = {};
                current = current[path[i]];
            }
            current[path[path.length - 1]] = decodeURIComponent(value);
            return acc;
        }, {});
    }
}

过程 2:更新中间件

修正自界说中间件以承受一个选项目标,并依据选项运用解析函数。

function customUrlEncodedParser(options = {}) {
    const extended = options.extended || false;
    return function (req, res, next) {
        if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
            let body = '';
            req.on('data', chunk => {
                body += chunk.toString(); // 将 Buffer 转换为字符串
            });
            req.on('end', () => {
                req.body = parseUrlEncoded(body, extended);
                next();
            });
        } else {
            next();
        }
    };
}

过程 3:运用带有选项的中间件

现在,您可以运用带有 extended 选项的这个中间件。

const express = require('express');
const app = express();
// 运用带有 extended 选项的自界说中间件
app.use(customUrlEncodedParser({ extended: true }));
app.post('/form-submit', (req, res) => {
    console.log(req.body); // 解析后的表单数据
    res.send('已收到表单数据');
});
app.listen(3000, () => console.log('服务器运行在 3000 端口'));

留意

这个完成供给了怎么完成 extended 选项的根本思路。实践的 express.urlencoded() 运用 { extended: true } 时会运用 qs 库,该库能够更好地处理杂乱的嵌套目标和数组。关于解析 URL 编码的数据,特别是处理杂乱结构时,建议在出产环境中依赖内置的 Express 中间件或直接运用 qs 库。


English version

what is the express.urlencoded

The express.urlencoded() middleware in Express.js is another built-in function that plays a crucial role in handling incoming requests. This middleware is specifically designed to parse incoming request bodies when the content type is application/x-www-form-urlencoded. This content type is commonly used in HTML forms. Here’s an overview of its principle and functionality:

Principle of express.urlencoded()

  1. Purpose:

    • The primary purpose of express.urlencoded() is to parse incoming request bodies in a format that web browsers typically use when sending data from a form using the POST method.
  2. Content Type:

    • It specifically handles the application/x-www-form-urlencoded content type. This format is standard for form submissions in HTML forms, where the form data is encoded as key-value pairs.

Functionality

  1. Parsing Form Data:

    • When a client submits data from a form, that data is sent to the server as a URL-encoded string (where characters are encoded as URL escape codes).
    • express.urlencoded() middleware parses this URL-encoded data into a JavaScript object.
  2. Attachment to Request Object:

    • After parsing, the middleware attaches the resulting object to the req.body property, similar to express.json(). This makes the form data easily accessible in the route handlers or subsequent middleware.
  3. Configuration Options:

    • extended: This option configures the middleware to use either the querystring library (when false) or the qs library (when true) for parsing. The qs library allows for a richer object creation, such as arrays and nested objects.
    • limit: Sets the maximum size of request bodies, providing control over the allowable amount of data.
  4. Common Usage:

    • Commonly used in scenarios where your server needs to accept data submitted from HTML forms.
    • Especially important for handling POST requests where form data is submitted.

Example Usage

const express = require('express');
const app = express();
// Activate express.urlencoded middleware
app.use(express.urlencoded({ extended: true }));
app.post('/form-submit', (req, res) => {
    console.log(req.body); // Form data from the client
    // ...rest of the route logic
});
app.listen(3000, () => console.log('Server running on port 3000'));

In this example, any POST request to /form-submit that sends data from an HTML form (with the content type application/x-www-form-urlencoded) will have its body parsed into a JavaScript object accessible through req.body.

Conclusion

express.urlencoded() is an essential middleware for handling form submissions in Express.js applications. Its ability to parse URL-encoded form data makes it indispensable for web applications where form handling is a common requirement. Just like express.json(), it’s a key component of the Express.js middleware ecosystem, facilitating the easy and efficient processing of client-submitted data.

DIY a express.urlencoded

Implementing a basic version of the express.urlencoded() middleware involves parsing URL-encoded data from the request body. This type of data is typically sent by HTML forms. The basic steps to create such a middleware are:

  1. Check the Content-Type: Ensure the request’s Content-Type is application/x-www-form-urlencoded.
  2. Read and Parse the Request Body: URL-encoded data is sent as a string in the request body. This string needs to be parsed into a JavaScript object.
  3. Attach the Parsed Data to req.body: After parsing, attach the resulting object to the req.body property for easy access in subsequent middleware or route handlers.

Here’s a step-by-step guide with corresponding code:

Step 1: Set Up Basic Middleware Structure

Define the structure of the middleware function. It should have three parameters: req, res, and next.

function customUrlEncodedParser(req, res, next) {
    // Middleware logic will go here
}

Step 2: Check Content-Type

Only proceed with parsing if the Content-Type is application/x-www-form-urlencoded.

function customUrlEncodedParser(req, res, next) {
    if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
        // Proceed with parsing
    } else {
        next(); // Skip this middleware if not URL-encoded
    }
}

Step 3: Read and Parse the Request Body

Read the request body using streams. URL-encoded data comes as a string, which we need to parse into key-value pairs.

function customUrlEncodedParser(req, res, next) {
    if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
        let body = '';
        req.on('data', chunk => {
            body += chunk.toString(); // convert Buffer to string
        });
        req.on('end', () => {
            req.body = parseUrlEncoded(body);
            next();
        });
    } else {
        next();
    }
}
function parseUrlEncoded(str) {
    const pairs = str.split('&');
    return pairs.reduce((acc, pair) => {
        const [key, value] = pair.split('=');
        acc[decodeURIComponent(key)] = decodeURIComponent(value);
        return acc;
    }, {});
}

Step 4: Using the Middleware in Your Express App

Use this middleware in your Express application just as you would with express.urlencoded().

const express = require('express');
const app = express();
app.use(customUrlEncodedParser);
app.post('/form-submit', (req, res) => {
    console.log(req.body); // Parsed form data
    res.send('Form data received');
});
app.listen(3000, () => console.log('Server running on port 3000'));

In this setup, any POST request to /form-submit with URL-encoded data (from an HTML form) will be parsed into a JavaScript object accessible through req.body.

Note

This implementation is a basic version for demonstration. Real-world scenarios might require handling more complex data structures, decoding nested objects, or dealing with arrays. The actual express.urlencoded() middleware is more sophisticated and handles various edge cases and configurations, making it a better choice for production environments.

extend to implement option config

The { extended: true } option in express.urlencoded({ extended: true }) is an important configuration setting that determines how the URL-encoded data is parsed. Specifically, it tells the middleware which parsing library to use:

  • When extended is set to true, the middleware uses the qs library for parsing. This library allows for rich objects and arrays to be encoded into the URL-encoded format, meaning it can handle nested objects.
  • When extended is set to false, the middleware uses the querystring library, which does not support nested objects.

To implement a basic version of this functionality, you can write a custom parsing function that mimics this behavior. Here’s how you can do it:

Step 1: Extended Parsing Function

First, define a function to handle the parsing based on the extended option. For simplicity, we’ll implement a basic way to parse nested objects when extended is true. A full implementation would require a more robust parsing algorithm or directly using the qs library.

function parseUrlEncoded(str, extended) {
    if (!extended) {
        // Simple parsing (not handling nested objects)
        return str.split('&').reduce((acc, pair) => {
            const [key, value] = pair.split('=');
            acc[decodeURIComponent(key)] = decodeURIComponent(value);
            return acc;
        }, {});
    } else {
        // Basic implementation for extended parsing (handling nested objects)
        // Note: This is for demonstration. A complete implementation would be more complex.
        return str.split('&').reduce((acc, pair) => {
            const [key, value] = pair.split('=');
            const path = key.split('[').map(k => k.replace(/]$/, ''));
            let current = acc;
            for (let i = 0; i < path.length - 1; i++) {
                if (!current[path[i]]) current[path[i]] = {};
                current = current[path[i]];
            }
            current[path[path.length - 1]] = decodeURIComponent(value);
            return acc;
        }, {});
    }
}

Step 2: Update the Middleware

Modify the custom middleware to accept an options object and use the parsing function accordingly.

function customUrlEncodedParser(options = {}) {
    const extended = options.extended || false;
    return function (req, res, next) {
        if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
            let body = '';
            req.on('data', chunk => {
                body += chunk.toString(); // Convert Buffer to string
            });
            req.on('end', () => {
                req.body = parseUrlEncoded(body, extended);
                next();
            });
        } else {
            next();
        }
    };
}

Step 3: Using the Middleware with Options

Now you can use this middleware with the extended option.

const express = require('express');
const app = express();
// Use the custom middleware with extended option
app.use(customUrlEncodedParser({ extended: true }));
app.post('/form-submit', (req, res) => {
    console.log(req.body); // Parsed form data
    res.send('Form data received');
});
app.listen(3000, () => console.log('Server running on port 3000'));

Note

This implementation provides a basic idea of how the extended option might be implemented. The actual express.urlencoded() with { extended: true } uses the qs library, which is much more capable of handling complex nested objects and arrays. For production use, relying on the built-in Express middleware or the qs library directly is recommended for parsing URL-encoded data, especially when dealing with complex structures.