前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Nestjs Fastify 响应压缩详解

Nestjs Fastify 响应压缩详解

原创
作者头像
DamonLiu
发布2022-11-26 15:16:57
1.3K0
发布2022-11-26 15:16:57
举报
文章被收录于专栏:知识技能知识技能

NestJs中使用Fastify时,需要使用 @fastify/compress 库进行压缩,官方实例代码

代码语言:javascript
复制
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的中参数

代码语言:javascript
复制
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插件如何判断是否需要进行压缩?

可以参看源码

代码语言:javascript
复制
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方法

代码语言:javascript
复制
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方法

代码语言:javascript
复制
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时不压缩

最后就是

代码语言:javascript
复制
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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档