NestJs中使用Fastify时,需要使用 @fastify/compress 库进行压缩,官方实例代码
import compression from '@fastify/compress';
await app.register(compression);
@fastify/compress 具体如何使用,可以从其Github首页学习。
这个插件可以自动给响应内容压缩,是否可以进行压缩,是根据请求响应的content-type来确定。
要注意,如果同时使用了 @fastify/static 插件,@fastify/compress 又是global模式,则需要保证 @fastify/compress 在 @fastify/static 之前注册
再看下@fastify/compress的中参数
type EncodingToken = 'br' | 'deflate' | 'gzip' | 'identity';
export interface FastifyCompressOptions {
brotliOptions?: BrotliOptions;
customTypes?: RegExp;
encodings?: EncodingToken[];
forceRequestEncoding?: EncodingToken;
global?: boolean;
inflateIfDeflated?: boolean;
onInvalidRequestPayload?: (encoding: string, request: FastifyRequest, error: Error) => Error | undefined | null;
onUnsupportedEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => string | Buffer | Stream;
onUnsupportedRequestEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => Error | undefined | null;
removeContentLengthHeader?: boolean;
requestEncodings?: EncodingToken[];
threshold?: number;
zlib?: unknown;
zlibOptions?: ZlibOptions;
}
其中的重要参数
threshold
响应体的大小最小是多少时会进行压缩,默认1024bytes
customTypes
使用 mime-db 库来确定响应类型是否需要压缩,可以用这个参数设置正则表达式压缩来其他类型的响应体,默认值 /^text\/(?!event-stream)|\+json$|\+text$|\+xml$|octet-stream$/
global
是否全局开启压缩,默认为true,会对所有响应进行处理,如果要关闭设置为false
encodings
采用的压缩算法的数组,可选值为br、deflate、gzip、identity(不压缩),数组前边的值比后边的值优先级高,Brotli压缩率更高,但是压缩更耗时,选用哪种压缩方式可以根据自己的业务情况做取舍
forceRequestEncoding
忽略content-encoding,强制使用设置的算法压缩
removeContentLengthHeader
是否删除响应头中的Content-Length,默认为true,会删除
onUnsupportedEncoding 当不支持编码时,可以通过设置 onUnsupportedEncoding(encoding, request, reply) 来修改响应并返回自定义返回,可以返回 string Buffer Stream Error
具体看下@fastify/compress插件如何判断是否需要进行压缩?
可以参看源码
const noCompress =
// don't compress on x-no-compression header
(req.headers['x-no-compression'] !== undefined) ||
// don't compress if not one of the indicated compressible types
(shouldCompress(reply.getHeader('Content-Type') || 'application/json', params.compressibleTypes) === false) ||
// don't compress on missing or identity `accept-encoding` header
((encoding = getEncodingHeader(params.encodings, req)) == null || encoding === 'identity')
首先是请求头明确说明不能压缩
看下shouldCompress方法
function shouldCompress (type, compressibleTypes) {
if (compressibleTypes.test(type)) return true
const data = mimedb[type.split(';', 1)[0].trim().toLowerCase()]
if (data === undefined) return false
return data.compressible === true
}
customTypes配置的正则匹配通过允许压缩,正则默认值是/^text\/(?!event-stream)|\+json$|\+text$|\+xml$|octet-stream$/,可以自行定义以实现自己的需求
大部分情况是根据响应头中的Content-Type匹配 mime-db 库是否可以进行压缩
再看下getEncodingHeader方法
function getEncodingHeader (encodings, request) {
let header = request.headers['accept-encoding']
if (header != null) {
header = header.toLowerCase()
// consider the no-preference token as gzip for downstream compat
// and x-gzip as an alias of gzip
// ref.: [HTTP/1.1 RFC 7230 section 4.2.3](https://datatracker.ietf.org/doc/html/rfc7230#section-4.2.3)
.replace(/\*|x-gzip/g, 'gzip')
return encodingNegotiator.negotiate(header, encodings)
} else {
return undefined
}
}
请求头中的accept-encoding的值未设置或者设置为identity时不压缩
最后就是
if (typeof payload.pipe !== 'function') {
if (Buffer.byteLength(payload) < params.threshold) {
return next()
}
payload = intoStream(payload)
}
响应体的大小要大于等于threshold设置的值,默认1024bytes,就会进行压缩
在大流量的生产环境,官方建议不要使用插件进行压缩,使用反向代理比如Nginx进行压缩
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。