Send 是一个用于将文件系统中的文件以 HTTP 响应形式进行流式传输的库,支持部分响应(Ranges)、条件 GET 协商(If-Match、If-Unmodified-Since、If-None-Match、If-Modified-Since)、高测试覆盖率,以及可用于在应用程序或框架中采取适当操作的细粒度事件。
这是一个可通过 npm registry 获取的 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 许可。