You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非Express环境下Node.js(Lambda)实现HTTP压缩并适配Postman

问题解答

关于compression库的使用

compression是Express专属的中间件,依赖Express的请求/响应处理流程,原生Node.js(包括AWS Lambda这种无服务器环境)没法直接用。没必要强行引入它,用Node.js内置的zlib模块完全能满足需求,还能减少依赖,更适合Lambda的轻量场景。

解决Postman/浏览器自动解析压缩响应的问题

你当前的问题出在两个核心点:

  • Lambda返回二进制压缩数据时,未设置isBase64Encoded: true,导致API Gateway把压缩后的Buffer转成Base64字符串返回
  • Content-Encoding头设置错误,同时写了gzip, deflate,但实际只用了deflate,且没有根据客户端支持的格式动态选择

具体修改步骤

  1. 解析客户端压缩支持:从请求头Accept-Encoding判断客户端能接受的压缩格式(优先选gzip,压缩率更高)
  2. 正确处理压缩数据:用zlib生成压缩Buffer,设置isBase64Encoded: true告诉API Gateway这是二进制数据
  3. 匹配正确响应头:只设置实际使用的压缩格式到Content-Encoding
  4. 保留合理ETag逻辑:ETag基于原始未压缩内容生成,确保缓存有效性

修改后的代码

import { APIGatewayProxyEvent } from 'aws-lambda'
import { getInfoFromDB } from './db/dbQueries'
import crypto from 'crypto'
import { transformInfoFromDBToJson } from './utils/transformationUtils'
import zlib from 'zlib'

export const handler = async (event: APIGatewayProxyEvent, context: any) => {
  try {
    // 获取原始数据并转成JSON字符串
    const rawData = transformInfoFromDBToJson(await getInfoFromDB())
    const responseBody = JSON.stringify(rawData)

    // 生成基于原始内容的ETag(保证缓存一致性)
    const freshETag = crypto.createHash('md5').update(responseBody).digest('hex')

    const MAX_AGE = process.env.CACHE_MAX_AGE
    const cacheControl = `max-age=${MAX_AGE}, must-revalidate`

    const headers: { [key: string]: string } = {
      ETag: freshETag,
      'Cache-Control': cacheControl,
      'Content-Type': 'application/json', // 明确内容类型,帮助客户端解析
    }

    let isCompressed = false
    let compressedBody: Buffer | undefined

    // 仅在开启压缩且客户端支持时执行压缩
    if (process.env.COMPRESS_RESPONSE === 'true') {
      const acceptEncoding = event.headers['Accept-Encoding'] || event.headers['accept-encoding'] || ''
      // 优先选择客户端支持的压缩格式
      if (acceptEncoding.includes('gzip')) {
        compressedBody = zlib.gzipSync(responseBody)
        headers['Content-Encoding'] = 'gzip'
        isCompressed = true
      } else if (acceptEncoding.includes('deflate')) {
        compressedBody = zlib.deflateSync(responseBody)
        headers['Content-Encoding'] = 'deflate'
        isCompressed = true
      }
    }

    // 返回对应内容:压缩后的二进制或原始字符串
    return {
      statusCode: 200,
      body: isCompressed ? compressedBody!.toString('base64') : responseBody,
      headers,
      isBase64Encoded: isCompressed, // 关键:告知API Gateway这是Base64编码的二进制数据
    }
  } catch (error) {
    console.error('Error fetching info:', error)
    return {
      statusCode: 500,
      body: JSON.stringify({ message: 'Error fetching info: Internal Server Error' }),
      headers: { 'Content-Type': 'application/json' },
    }
  }
}

关键修改说明

  • 添加Content-Type头:明确告诉客户端返回的是JSON格式,避免解析歧义
  • 动态判断压缩格式:根据客户端的Accept-Encoding头选择合适的压缩算法,兼容性更好
  • 设置isBase64Encoded:这是让API Gateway正确传递二进制压缩数据的核心,客户端收到后会自动解码
  • ETag基于原始内容:不管是否压缩,ETag都用原始数据生成,确保缓存系统能正确识别内容是否变化

内容的提问来源于stack exchange,提问作者Allanh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:55:58