
ファイルをHTTPレスポンスとしてストリーミングするNode.jsライブラリ。部分コンテンツ、条件付きリクエスト、設定可能なキャッシュヘッダーをサポートします。FastifyなどのWebフレームワークでの使用を想定しています。
Sendは、ファイルシステムからHTTPレスポンスとしてファイルをストリーミングするためのライブラリです。部分レスポンス(Ranges)、条件付きGETネゴシエーション(If-Match、If-Unmodified-Since、If-None-Match、If-Modified-Since)、高いテストカバレッジ、そしてアプリケーションやフレームワーク内で適切なアクションを実行するために活用できる詳細なイベントをサポートしています。
これはnpmレジストリを通じて利用可能なNode.jsモジュールです。インストールはnpm installコマンドを使用して行います:
$ npm install @fastify/send
TypeScript を使用する場合は @types/mime@3 を使用する必要があります。
@types/mime@4 では mime の型が削除されました。
$ npm install -D @types/mime@3
const send = require('@fastify/send')
指定されたパスに対して statusCode、headers、stream を提供し、res に送信します。req は Node.js の HTTP リクエストであり、path は送信する urlencoded されたパスです(urlencoded であり、実際のファイルシステムパスではありません)。
レンジリクエストの受け入れを有効または無効にします。デフォルトは true です。
無効にすると Accept-Ranges を送信せず、Range リクエストヘッダーの内容を無視します。
Cache-Control レスポンスヘッダーの設定を有効または無効にします。デフォルトは true です。無効にすると immutable および maxAge オプションが無視されます。
デフォルトでは、このライブラリは mime モジュールを使用して、リクエストされたファイルの拡張子に基づいてレスポンスの Content-Type を設定します。
この機能を無効にするには、contentType を false に設定します。
無効にした場合、Content-Type ヘッダーは手動で設定する必要があります。
"ドットファイル" に遭遇した際の扱いを設定します。ドットファイルとは、ドット (".") で始まるファイルまたはディレクトリのことです。このチェックはパス自体に対して行われ、パスがディスク上に存在するかどうかは確認されないことに注意してください。root が指定されている場合、root より上のドットファイルのみがチェックされます(つまり、"deny" に設定されている場合、root 自体がドットファイル内にあっても構いません)。
'allow' ドットファイルに対して特別な扱いを行いません。'deny' ドットファイルへのリクエストに対して 403 を送信します。'ignore' ドットファイルが存在しないものとして扱い、404 を返します。デフォルト値は 'ignore' に 類似 していますが、後方互換性のため、ドットで始まるディレクトリ内のファイルは無視されないという例外があります。
ストリームが終了するバイトオフセット。デフォルトはファイル長から 1 を引いた値です。終了位置はストリームに含まれ、end: 3 はストリームの 4 バイト目を含むことを意味します。
etag の生成を有効または無効にします。デフォルトは true です。
指定されたファイルが存在しない場合、指定された拡張子を指定された順序で付加して試します。デフォルトでは無効(false に設定)です。拡張子のない HTML ファイルを配信する例: ['html', 'htm']。リクエストされたファイルにすでに拡張子がある場合はスキップされます。
Cache-Control レスポンスヘッダーの immutable ディレクティブを有効または無効にします。デフォルトは false です。true に設定する場合、キャッシュを有効にするために maxAge オプションも指定する必要があります。immutable ディレクティブは、対応クライアントが maxAge オプションの有効期間中にファイルが変更されたかどうかを確認するための条件付きリクエストを行うことを防ぎます。
デフォルトでは send は "index.html" ファイルをサポートしています。無効にするには false を設定するか、新しいインデックスを優先順に文字列または配列で指定します。
Last-Modified ヘッダーを有効または無効にします。デフォルトは true です。ファイルシステムの最終更新値を使用します。
HTTP キャッシュ用の max-age をミリ秒で指定します。デフォルトは 0 です。 ms モジュールが受け入れる文字列でも指定できます。
レスポンスコンテンツの最大サイズを指定します。デフォルトはファイル全体のサイズです。これは acceptRanges が true の場合に使用されます。
ファイル解決後、レスポンス処理およびファイルストリーム作成の前に、最終的に選択されたファイルの絶対パスとファイルシステムの統計情報を引数として呼び出されます。コールバックは同期でも、Promise を返してもかまいません。Promise を返す場合、send はそれが解決するまで待機します。コールバックが例外をスローするか、返された Promise が拒否された場合、操作は中止され send() は拒否されます。
path を基準にファイルを配信します。
ストリームが開始するバイトオフセット。デフォルトは 0 です。開始位置はストリームに含まれ、start: 2 はストリームの 3 バイト目を含むことを意味します。
指定された場合、このオプションは基盤となるリソースからの読み取りを一時停止する前に、内部バッファが保持する最大バイト数を設定します。このオプションを省略した場合(または undefined を渡した場合)、Node.js は読み取り可能なバイナリストリームの組み込みデフォルトにフォールバックします。
mime エクスポートは、mime npm モジュールのグローバルインスタンスです。
これは、ファイル拡張子に関連付けられた MIME タイプや、ファイルの MIME タイプを解決する方法に関するその他のオプション(未知のファイル拡張子に使用するデフォルトタイプなど)を設定するために使用されます。
内部キャッシュは_行いません_。これには Varnish などのリバースプロキシキャッシュ、または CDN と呼ばれるあの便利なものを使用してください。アプリケーションがシングルノードのメモリキャッシュの恩恵を受けるほど小規模であれば、そもそもキャッシュを必要としないほど小規模です ;)。
debug() の計測出力を有効にするには、NODE_DEBUG をエクスポートします:
$ NODE_DEBUG=send node app
$ npm install
$ npm test
このシンプルな例では、すべてのリクエストに対して特定のファイルを送信します。
const http = require('node:http')
const send = require('send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, '/path/to/index.html')
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
このシンプルな例では、指定したディレクトリ内のすべてのファイルをトップレベルとして配信するだけです。例えば、リクエスト GET /foo.txt は /www/public/foo.txt を返します。
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Default unknown types to text/plain
send.mime.default_type = 'text/plain'
// Add a custom type
send.mime.define({
'application/x-my-type': ['x-mt', 'x-mtt']
})
const server = http.createServer(function onRequest (req, res) {
const { statusCode, headers, stream } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
res.writeHead(statusCode, headers)
stream.pipe(res)
})
server.listen(3000)
これは、ディレクトリの一覧をレンダリングするためのカスタム関数を用いて、 ディレクトリ構造を配信する例です。
const http = require('node:http')
const fs = require('node:fs')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
// Transfer arbitrary files from within /www/example.com/public/*
// with a custom handler for directory listing
const server = http.createServer(async function onRequest (req, res) {
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { index: false, root: '/www/public' })
if(type === 'directory') {
// get directory list
const list = await readdir(metadata.path)
// render an index for the directory
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end(list.join('\n') + '\n')
} else {
res.writeHead(statusCode, headers)
stream.pipe(res)
}
})
server.listen(3000)
const http = require('node:http')
const parseUrl = require('parseurl')
const send = require('@fastify/send')
const server = http.createServer(async function onRequest (req, res) {
// transfer arbitrary files from within
// /www/example.com/public/*
const { statusCode, headers, stream, type, metadata } = await send(req, parseUrl(req).pathname, { root: '/www/public' })
switch (type) {
case 'directory': {
// your custom directory handling logic:
res.writeHead(301, {
'Location': metadata.requestPath + '/'
})
res.end('Redirecting to ' + metadata.requestPath + '/')
break
}
case 'error': {
// your custom error-handling logic:
res.writeHead(metadata.error.status ?? 500, {})
res.end(metadata.error.message)
break
}
default: {
// your custom headers
// serve all files for download
res.setHeader('Content-Disposition', 'attachment')
res.writeHead(statusCode, headers)
stream.pipe(res)
}
}
})
server.listen(3000)
MIT の下でライセンスされています。