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,则仅检查根目录之上的点文件(即,当设置为 "deny" 时,根目录本身可以位于点文件内)。
'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 缓存的最大年龄(以毫秒为单位),默认为 0。也可以是 ms 模块接受的字符串。
指定最大响应内容大小,默认为整个文件大小。当 acceptRanges 为 true 时使用此选项。
相对于 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 许可证。