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

Starlette如何正确提供预压缩gz文件并规避修改request.url属性报错

Starlette返回预压缩.gz静态资源的正确实现方案

问题原因说明

  • 首先AttributeError: Can't set attribute报错是因为Starlette的URL对象是不可变类型,设计层面禁止直接修改属性,且修改请求路径的思路本身不符合Starlette的设计逻辑,不需要效仿Express的实现方式。
  • 直接返回.gz文件内容浏览器无法识别,是因为响应头缺少两个必要字段:
    • 没有Content-Encoding: gzip声明内容是gzip压缩格式
    • 直接复用S3返回的头会导致Content-Type被设置为application/gzip之类的压缩文件类型,而非原资源的text/css、application/javascript等正确MIME类型

正确实现方案

你不需要修改请求路径,只需要在返回响应的时候手动修正响应头即可,修改后的代码如下:

import mimetypes
async def theme(request):
  try:
    file_path = request.path_params.get('file_path')
    # 提前获取原文件的MIME类型
    content_type, _ = mimetypes.guess_type(file_path)
    is_asset = file_path.split('.')[-1] in ['ico', 'png']
    use_gzip = False
    if is_asset:
      full_path = f'assets/{file_path}'
    else:
      # 兼容没有Accept-Encoding头的情况,避免KeyError
      accept_encoding = request.headers.get('accept-encoding', '')
      if 'gzip' in accept_encoding.lower():
        use_gzip = True
        full_path = f'theme_build/{file_path}.gz'
      else:
        full_path = f'theme_build/{file_path}'
    print(full_path, flush=True)
    s3_result = get_file(full_path)
    # 复制S3返回的头,再修改必要字段
    response_headers = s3_result['ResponseMetadata']['HTTPHeaders'].copy()
    # 修正Content-Type为原文件的正确类型
    if content_type:
      response_headers['Content-Type'] = content_type
    if use_gzip:
      # 声明内容为gzip压缩
      response_headers['Content-Encoding'] = 'gzip'
      # 通知缓存服务器根据Accept-Encoding返回不同内容
      response_headers['Vary'] = 'Accept-Encoding'
    return StreamingResponse(
      s3_result['Body'], 
      headers=response_headers
    )
  except ...:
    # 你的异常处理逻辑

注意事项

  • 如果S3存储的.gz文件自带了Content-Length头可以直接保留,不需要额外修改
  • 对于图片、图标这类已经是压缩格式的资源,不需要走gzip逻辑,你原来的判断逻辑可以保留
  • 如果你的S3桶内的.gz文件已经配置了正确的头,也可以直接用,但手动覆盖响应头兼容性更强,不容易因为S3配置错误出现问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 16:06:03