ContentTypeParser
Content-Type
パーサー
Fastifyはネイティブで'application/json'
と'text/plain'
のコンテンツタイプのみをサポートしています。コンテンツタイプがこれらのいずれでもない場合、FST_ERR_CTP_INVALID_MEDIA_TYPE
エラーがスローされます。その他の一般的なコンテンツタイプは、プラグインを使用してサポートされます。
デフォルトの文字セットはutf-8
です。異なるコンテンツタイプをサポートする必要がある場合は、addContentTypeParser
APIを使用できます。 _デフォルトのJSONまたはプレーンテキストパーサーは変更または削除できます。_
注意: Content-Type
ヘッダーで独自のコンテンツタイプを指定する場合、UTF-8はデフォルトになりません。text/html; charset=utf-8
のようにUTF-8を含めてください。
他のAPIと同様に、addContentTypeParser
は宣言されたスコープにカプセル化されます。これは、ルートスコープで宣言するとどこでも使用できますが、プラグイン内で宣言すると、そのスコープとその子でのみ使用できることを意味します。
Fastifyは、解析されたリクエストペイロードをFastifyリクエストオブジェクトに自動的に追加します。これはrequest.body
でアクセスできます。
GET
およびHEAD
リクエストの場合、ペイロードは解析されません。 OPTIONS
およびDELETE
リクエストの場合、ペイロードはcontent-typeヘッダーでコンテンツタイプが指定されている場合にのみ解析されます。指定されていない場合、POST
、PUT
、PATCH
のようにキャッチオールパーサーは実行されず、ペイロードは単に解析されません。
⚠ セキュリティに関する注意
正規表現を使用して
Content-Type
を検出する場合、Content-Type
を適切に検出する方法に注意する必要があります。たとえば、application/*
が必要な場合は、エッセンスMIMEタイプのみを一致させるために/^application\/([\w-]+);?/
を使用する必要があります。
使用方法
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) {
var 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は、一致するRegExp
を見つける前に、最初にstring
値を持つcontent-typeパーサーとの一致を試みます。重複するコンテンツタイプを提供する場合、Fastifyは、渡された最後のコンテンツタイプから始めて最初のコンテンツタイプで終わることで、一致するコンテンツタイプを見つけようとします。そのため、一般的なコンテンツタイプをより正確に指定する場合は、以下の例のように、最初に一般的なコンテンツタイプを指定してから、より具体的なコンテンツタイプを指定します。
// 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) => {} )
fastify.registerでaddContentTypeParserを使用する
fastify.register
と組み合わせてaddContentTypeParser
を使用する場合、ルートを登録するときにawait
を使用しないでください。 await
を使用すると、ルートの登録が非同期になり、addContentTypeParserが設定される前にルートが登録される可能性があります。
正しい使用方法
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
APIに加えて、さらに使用できるAPIがあります。これらはhasContentTypeParser
、removeContentTypeParser
、およびremoveAllContentTypeParsers
です。
hasContentTypeParser
hasContentTypeParser
APIを使用して、特定のコンテンツタイプパーサーが既に存在するかどうかを確認できます。
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
コンテンツタイプをサポートしています。
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
すぐ上の例では、削除したい各コンテンツタイプを指定する必要があることに気付くでしょう。この問題を解決するために、FastifyはremoveAllContentTypeParsers
APIを提供しています。これは、現在存在するすべてのコンテンツタイプパーサーを削除するために使用できます。以下の例では、削除する各コンテンツタイプを指定する必要がないことを除いて、上記の例と同じことを実現します。 removeContentTypeParser
と同様に、このAPIはカプセル化をサポートしています。このAPIは、すべてのコンテンツタイプに対して実行されるキャッチオールコンテンツタイプパーサーを登録し、組み込みパーサーも無視する場合に特に役立ちます。
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('text/xml', function (request, payload, done) {
xmlParser(payload, function (err, body) {
done(err, body)
})
})
**注意**: パーサーの古い構文`function(req, done)`と`async function(req)`はまだサポートされていますが、非推奨です。
ボディパーサー
リクエストの本文は2つの方法で解析できます。1つ目は上記のとおりです。カスタムコンテンツタイプパーサーを追加して、リクエストストリームを処理します。2つ目では、本文を取得する方法を宣言するparseAs
オプションをaddContentTypeParser
APIに渡す必要があります。これは、'string'
または'buffer'
タイプのいずれかになります。 parseAs
オプションを使用すると、Fastifyは内部でストリームを処理し、本文の最大サイズやコンテンツの長さなど、いくつかのチェックを実行します。制限を超えると、カスタムパーサーは呼び出されません。
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
try {
var json = JSON.parse(body)
done(null, json)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
例については、example/parser.js
を参照してください。
カスタムパーサーオプション
parseAs
(文字列): 受信データをどのように収集するかを指定する'string'
または'buffer'
のいずれか。デフォルト:'buffer'
。bodyLimit
(数値): カスタムパーサーが受け入れる最大ペイロードサイズ(バイト単位)。デフォルトは、Fastifyファクトリ関数
に渡されるグローバルボディ制限です。
キャッチオール
コンテンツタイプに関係なくすべてのリクエストをキャッチする必要がある場合があります。Fastifyでは、'*'
コンテンツタイプを使用するだけです。
fastify.addContentTypeParser('*', function (request, payload, done) {
var data = ''
payload.on('data', chunk => { data += chunk })
payload.on('end', () => {
done(null, data)
})
})
これを使用すると、対応するコンテンツタイプパーサーがないすべてのリクエストは、指定された関数によって処理されます。
これは、リクエストストリームをパイプするのにも役立ちます。次のようなコンテンツパーサーを定義できます
fastify.addContentTypeParser('*', function (request, payload, done) {
done()
})
次に、コアHTTPリクエストに直接アクセスして、必要な場所にパイプします
app.post('/hello', (request, reply) => {
reply.send(request.raw)
})
受信json lineオブジェクトをログに記録する完全な例を次に示します
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
}
})
ファイルのアップロードをパイプする場合は、このプラグインを確認してください。
特定のコンテンツタイプがないコンテンツタイプだけでなく、すべてのコンテンツタイプでコンテンツタイプパーサーを実行する場合は、最初にremoveAllContentTypeParsers
メソッドを呼び出す必要があります。
// 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) {
var data = ''
payload.on('data', chunk => { data += chunk })
payload.on('end', () => {
done(null, data)
})
})