Content-Type 解析器
Content-Type 解析器
¥Content-Type Parser
Fastify 原生支持 'application/json' 和 'text/plain' 内容类型,默认字符集为 utf-8。这些默认解析器可以更改或删除。
¥Fastify natively supports 'application/json' and 'text/plain' content types
with a default charset of utf-8. These default parsers can be changed or
removed.
不支持的内容类型将引发 FST_ERR_CTP_INVALID_MEDIA_TYPE 错误。
¥Unsupported content types will throw an FST_ERR_CTP_INVALID_MEDIA_TYPE error.
要支持其他内容类型,请使用 addContentTypeParser API 或现有的 plugin。
¥To support other content types, use the addContentTypeParser API or an
existing plugin.
与其他 API 一样,addContentTypeParser 封装在声明它的范围中。如果在根作用域中声明,则它在任何地方都可用;如果在插件中声明,则它仅在该范围及其子范围内可用。
¥As with other APIs, addContentTypeParser is encapsulated in the scope in which
it is declared. If declared in the root scope, it is available everywhere; if
declared in a plugin, it is available only in that scope and its children.
Fastify 会自动将解析后的请求负载添加到 Fastify 请求 对象,可通过 request.body 访问。
¥Fastify automatically adds the parsed request payload to the Fastify
request object, accessible via request.body.
请注意,对于 GET 和 HEAD 请求,有效负载永远不会被解析。对于 OPTIONS 和 DELETE 请求,仅当提供有效的 content-type 标头时才会解析有效负载。与 POST、PUT 和 PATCH 不同,catch-all 解析器不会被执行,并且负载不会被解析。
¥Note that for GET and HEAD requests, the payload is never parsed. For
OPTIONS and DELETE requests, the payload is parsed only if a valid
content-type header is provided. Unlike POST, PUT, and PATCH, the
catch-all parser is not executed, and the payload is simply not
parsed.
⚠ 警告:使用正则表达式检测
Content-Type时,确保正确检测非常重要。例如,要匹配application/*,请使用/^application\/([\w-]+);?/仅匹配 本质 MIME 类型。¥⚠ Warning: When using regular expressions to detect
Content-Type, it is important to ensure proper detection. For example, to matchapplication/*, use/^application\/([\w-]+);?/to match the essence MIME type only.
用法
¥Usage
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) {
jsoffParser(payload, function (err, body) {
done(err, body)
})
})
// Handle multiple content types with the same function
fastify.addContentTypeParser(['text/xml', 'application/xml'], function (request, payload, done) {
xmlParser(payload, function (err, body) {
done(err, body)
})
})
// Async is also supported in Node versions >= 8.0.0
fastify.addContentTypeParser('application/jsoff', async function (request, payload) {
const res = await jsoffParserAsync(payload)
return res
})
// Handle all content types that matches RegExp
fastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) {
imageParser(payload, function (err, body) {
done(err, body)
})
})
// Can use default JSON/Text parser for different content Types
fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
Fastify 首先尝试将内容类型解析器与 string 值匹配,然后再尝试查找匹配的 RegExp。对于重叠的内容类型,它从配置的最后一个开始,以第一个结束(后进先出)。要更精确地指定一般内容类型,请首先指定一般类型,然后指定特定类型,如下所示。
¥Fastify first tries to match a content-type parser with a string value before
trying to find a matching RegExp. For overlapping content types, it starts
with the last one configured and ends with the first (last in, first out).
To specify a general content type more precisely, first specify the general
type, then the specific one, as shown below.
// Here only the second content type parser is called because its value also matches the first one
fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )
// Here the desired behavior is achieved because fastify first tries to match the
// `application/vnd.custom+xml` content type parser
fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )
fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
使用 addContentTypeParser 和 fastify.register
¥Using addContentTypeParser with fastify.register
当将 addContentTypeParser 与 fastify.register 一起使用时,注册路由时请避免使用 await。使用 await 使路由注册异步,可能在设置 addContentTypeParser 之前注册路由。
¥When using addContentTypeParser with fastify.register, avoid await
when registering routes. Using await makes route registration asynchronous,
potentially registering routes before addContentTypeParser is set.
正确用法
¥Correct Usage
const fastify = require('fastify')();
fastify.register((fastify, opts) => {
fastify.addContentTypeParser('application/json', function (request, payload, done) {
jsonParser(payload, function (err, body) {
done(err, body)
})
})
fastify.get('/hello', async (req, res) => {});
});
除了 addContentTypeParser,hasContentTypeParser、removeContentTypeParser 和 removeAllContentTypeParsers API 也可用。
¥In addition to addContentTypeParser, the hasContentTypeParser,
removeContentTypeParser, and removeAllContentTypeParsers APIs are available.
hasContentTypeParser
使用 hasContentTypeParser API 检查是否存在特定内容类型解析器。
¥Use the hasContentTypeParser API to check if a specific content type parser
exists.
if (!fastify.hasContentTypeParser('application/jsoff')){
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) {
jsoffParser(payload, function (err, body) {
done(err, body)
})
})
}
removeContentTypeParser
removeContentTypeParser 可以删除单个内容类型或内容类型数组,同时支持 string 和 RegExp。
¥removeContentTypeParser can remove a single content type or an array of
content types, supporting both string and RegExp.
fastify.addContentTypeParser('text/xml', function (request, payload, done) {
xmlParser(payload, function (err, body) {
done(err, body)
})
})
// Removes the both built-in content type parsers so that only the content type parser for text/html is available
fastify.removeContentTypeParser(['application/json', 'text/plain'])
removeAllContentTypeParsers
removeAllContentTypeParsers API 删除了所有现有的内容类型解析器,无需单独指定每个解析器。此 API 支持封装,可用于注册应该为每种内容类型执行的 包罗万象的内容类型解析器,忽略内置解析器。
¥The removeAllContentTypeParsers API removes all existing content type parsers
eliminating the need to specify each one individually. This API supports
encapsulation and is useful for registering a
catch-all content type parser that should be executed for every
content type, ignoring built-in parsers.
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('text/xml', function (request, payload, done) {
xmlParser(payload, function (err, body) {
done(err, body)
})
})
ℹ️ 注意:
function(req, done)和async function(req)仍受支持,但已弃用。¥ℹ️ Note:
function(req, done)andasync function(req)are still supported but deprecated.
正文解析器
¥Body Parser
请求主体可以通过两种方式解析。首先,添加自定义内容类型解析器并处理请求流。或者其次,使用 addContentTypeParser API 中的 parseAs 选项,指定 'string' 或 'buffer'。Fastify 将处理流,检查主体的 最大尺寸 和内容长度。如果超出限制,则不会调用自定义解析器。
¥The request body can be parsed in two ways. First, add a custom content type
parser and handle the request stream. Or second, use the parseAs option in the
addContentTypeParser API, specifying 'string' or 'buffer'. Fastify will
handle the stream, check the maximum size of
the body, and the content length. If the limit is exceeded, the custom parser
will not be invoked.
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
try {
const json = JSON.parse(body)
done(null, json)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
请参阅 example/parser.js 了解示例。
¥See
example/parser.js
for an example.
自定义解析器选项
¥Custom Parser Options
-
parseAs(字符串):'string'或'buffer'指定应如何收集传入数据。默认:'buffer'。¥
parseAs(string):'string'or'buffer'to designate how the incoming data should be collected. Default:'buffer'. -
bodyLimit(数字):自定义解析器将接受的最大有效负载大小(以字节为单位)。默认为传递给Fastify factory function的全局主体限制。¥
bodyLimit(number): The maximum payload size, in bytes, that the custom parser will accept. Defaults to the global body limit passed to theFastify factory function.
Catch-All
要捕获所有请求(无论内容类型如何),请使用 '*' 内容类型:
¥To catch all requests regardless of content type, use the '*' content type:
fastify.addContentTypeParser('*', function (request, payload, done) {
let data = ''
payload.on('data', chunk => { data += chunk })
payload.on('end', () => {
done(null, data)
})
})
此函数将处理所有没有相应内容类型解析器的请求。
¥All requests without a corresponding content type parser will be handled by this function.
这对于管道请求流也很有用。定义内容解析器,例如:
¥This is also useful for piping the request stream. Define a content parser like:
fastify.addContentTypeParser('*', function (request, payload, done) {
done()
})
然后直接访问核心 HTTP 请求进行管道:
¥And then access the core HTTP request directly for piping:
app.post('/hello', (request, reply) => {
reply.send(request.raw)
})
这是一个记录传入 json 行 对象的完整示例:
¥Here is a complete example that logs incoming json line objects:
const split2 = require('split2')
const pump = require('pump')
fastify.addContentTypeParser('*', (request, payload, done) => {
done(null, pump(payload, split2(JSON.parse)))
})
fastify.route({
method: 'POST',
url: '/api/log/jsons',
handler: (req, res) => {
req.body.on('data', d => console.log(d)) // log every incoming object
}
})
对于管道文件上传,请查看 @fastify/multipart。
¥For piping file uploads, check out
@fastify/multipart.
要对所有内容类型执行内容类型解析器,请先调用 removeAllContentTypeParsers。
¥To execute the content type parser on all content types, call
removeAllContentTypeParsers first.
// Without this call, the request body with the content type application/json would be processed by the built-in JSON parser
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('*', function (request, payload, done) {
const data = ''
payload.on('data', chunk => { data += chunk })
payload.on('end', () => {
done(null, data)
})
})