当请求未压缩时,使用 Starlette 提供预压缩文件,但 'accept-encoding' 包括 'gzip'

serve pre-compressed files with Starlette, when uncompressed is requested, but 'accept-encoding' includes 'gzip'

假设为request.url

GET /fomantic-ui/default/semantic.min.css

对于某些文件扩展名,例如.css,我需要提供预压缩的 .gz 版本。

我从 node-express 知道一种方法,当应用于 Starlette 时,只需操作 request.url.path 并向其附加 '.gz'。然而,这会导致 AttributeError: Can't set attribute.

Starlette 世界的方法是什么?

我唯一发现的是应该处理 GZIP 请求的中间件。但我认为它在这里不可用,因为我需要自己的逻辑来决定从 AWS S3 存储桶或 diskcache.

请求什么文件

这是路由处理程序的示例:

async def theme(request):
  try:
    file_path = request.path_params.get('file_path')
    is_asset = file_path.split('.')[-1] in ['ico', 'png']
    if is_asset:
      full_path = f'assets/{file_path}'
    else:
      if 'gzip' in request.headers['accept-encoding']:
        full_path = f'theme_build/{file_path}.gz'
        request.url.path = request.url.path + '.gz' # results in AttributeError("can't set attribute")
      else:
        full_path = f'theme_build/{file_path}'
    print(full_path, flush=True)
    s3_result = get_file(full_path)
    return StreamingResponse(s3_result['Body'], headers=s3_result['ResponseMetadata']['HTTPHeaders'])
  except ...

显然我不能只return gzip 内容作为对原始 request.url 的响应,因为浏览器不会期望 gzip 内容。

可能完全正确的方法是在响应的 header 中设置 'content-encoding': 'gzip'

所以,在上面的例子中我基本上是这样做的:

return StreamingResponse(
    s3_result['Body'],
    headers={**s3_result['ResponseMetadata']['HTTPHeaders'], 'content-encoding': 'gzip'}
)