无法在使用gzip从Node后端提供的静态资源中关闭nginx的分块传输编码

11
我们有一个使用Node/express构建的Web应用程序,除了正常内容外,还提供静态资源服务,通过express.static()实现。在它前面有一个nginx服务器,如果用户代理支持,它当前配置为gzip这些静态资源请求。
但是,尽管nginx按预期进行了gzip处理,但它从原始响应中删除Content-Length标头,并设置Transfer-Encoding: chunked。这会破坏我们CDN上的缓存。
以下是来自Node后端和nginx的典型静态资源请求(JS文件)的响应: 请求:
curl -s -D - 'http://my_node_app/res/my_js.js' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Connection: keep-alive' --compressed -o /dev/null

从 Node 返回的响应头:

HTTP/1.1 200 OK
Accept-Ranges: bytes
Date: Wed, 07 Jan 2015 02:24:55 GMT
Cache-Control: public, max-age=0
Last-Modified: Wed, 07 Jan 2015 01:12:05 GMT
Content-Type: application/javascript
Content-Length: 37386   // <--- The expected header
Connection: keep-alive

nginx 响应头:

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 07 Jan 2015 02:24:55 GMT
Content-Type: application/javascript
Transfer-Encoding: chunked  // <--- The problematic header
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: public, max-age=0
Last-Modified: Wed, 07 Jan 2015 01:12:05 GMT
Content-Encoding: gzip

我们当前的静态资源 locationnginx 配置如下:

nginx 配置

# cache file paths that start with /res/
location /res/ {
    limit_except GET HEAD { }

    # http://nginx.com/resources/admin-guide/caching/
    # http://nginx.org/en/docs/http/ngx_http_proxy_module.html

    proxy_buffers 8 128k;
    #proxy_buffer_size 256k;
    #proxy_busy_buffers_size 256k;

    # The cache depends on proxy buffers, and will not work if proxy_buffering is set to off.
    proxy_buffering     on;
    proxy_http_version  1.1;
    proxy_set_header  Connection "";
    proxy_connect_timeout  2s;
    proxy_read_timeout  5s;
    proxy_pass          http://node_backend;

    chunked_transfer_encoding off;

    proxy_cache         my_app;
    proxy_cache_valid   15m;
    proxy_cache_key     $uri$is_args$args;
}
从上面的配置可以看出,尽管按照nginx文档的要求对这些路径显式设置了 chunked_transfer_encodingoff,并且启用了 proxy_buffering 和足够大的 proxy_buffers 大小,但响应仍然是分块传输的。我们错过了什么吗?
--编辑1:版本信息--
$ nginx -v
nginx version: nginx/1.6.1

$ node -v
v0.10.30

--编辑2:nginx gzip配置--

# http://nginx.org/en/docs/http/ngx_http_gzip_module.html
gzip on;
gzip_buffers 32 4k;
gzip_comp_level 1;
gzip_min_length 1000;
#gzip_http_version 1.0;
gzip_types application/javascript text/css
gzip_proxied any;
gzip_vary on;

1
你在哪里告诉nginx进行gzip压缩?它正在执行流式gzip压缩,对于这种情况,分块是唯一明智的选择。相反,你应该将静态资产以原始和gzip格式保存,并配置nginx在请求时提供gzip压缩的资产。换句话说,预先在服务器端进行gzip压缩而不是实时压缩。 - generalhenry
@generalhenry,我也添加了gzip配置。你说得对,资产正在动态压缩。我还看到了gzip_static模块,可以帮助实现你所描述的功能。因此,在我们的情况下,我们要么必须在nginx上托管原始+gzipped资产,配置gzip_static,然后它会做正确的事情。或者,在我们的资产构建阶段中预先构建它们,在Node上构建一些智能,以根据当前请求提供其中之一,并关闭nginx上的gzip - kodeninja
是的,gzip_proxied any; 看起来就是罪魁祸首了(免责声明,我并不是nginx方面的专家,只是从数据流的角度出发考虑问题)。 - generalhenry
1
你好,这个问题有解决方案了吗?我们也遇到了同样的问题。 - jigneshbrahmkhatri
我也遇到了同样的问题,参考了http://serverfault.com/questions/745153/images-failed-to-load-resource-the-network-connection-was-lost。我尝试在nginx上关闭gzip和chunked_transfer_encoding,并在node.js中设置响应头`res.header('transfer-encoding', ''); res.header('Content-Length', 0);`,但这些都没有起作用... - user1575921
1个回答

2
您是正确的,让我详细解释一下。
首先需要发送的是头部信息。但是由于您正在使用流压缩,最终大小是不确定的。您仅知道未压缩资源的大小,发送过大的Content-Length也是不正确的。
因此,有两种选择:
1.传输编码块
2.在发送任何数据之前完全压缩资源,这样可以得知压缩后的大小。
目前,您正在遇到第一种情况,听起来您确实需要第二种情况。获得第二种情况的最简单方法是像评论中@kodeninja所说,开启gzip_static。

如何实现代理传递(而不是提到的gzip_static)? - Brandon Ros

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接