我使用 nginx 1.2.3 来代理一个脚本:
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8880;
proxy_buffering off;
proxy_read_timeout 300s;
gzip off;
脚本同时发送Transfer-encoding: chunked
和Content-Length: 251
:
HTTP/1.0 307 Temporary Redirect
Content-length: 251
Pragma: no-cache
Location: /...
Cache-control: no-cache
Transfer-encoding: chunked
我两者都需要,但是 nginx 会自动删除Content-Length
:
HTTP/1.1 302 Found
Server: nginx/1.2.3
Content-Type: application/json; charset=utf-8
Content-Length: 58
Connection: keep-alive
Location: /...
因此,客户端不会等待块被发送。这曾经在早期版本的 nginx 中起作用。
答案1
不幸的是,我无法对 cnst 的帖子发表评论 - 因此我将在这里回答。
该nginx_http_proxy
模块默认以 HTTP/1.0 与上游通信。这可以通过指令进行更改proxy_http_version 1.1
。
这也可能是您的脚本返回 HTTP/1.0 答案的原因,尽管307
此版本中不存在分块编码和状态代码。
你不应该使用分块编码重定向因为这确实没有任何意义。
此外,好像是 nginx不传递块从上游到客户端一个接一个,但它缓冲上游的响应。Content-Length
由于违反了定义,因此忽略了标头字段。我不得不查看源代码因为所有这些似乎都没有记录。
您可能想要尝试将nginx_tcp_proxy_module
分块内容代理为原始 TCP 数据:Github 上的模块
更新(10.04.14)
该
nginx_http_proxy
模块支持X-Accel-*
标题,其中一个(X-Accel-Buffering: yes|no
)控制响应是否应该缓冲。
将此标头(X-Accel-Buffering: no
)添加到后端的响应将导致 nginx 直接将块传递给客户端。
此标头允许控制根据请求。
该模块还具有配置指令 proxy_buffering
启用或禁用响应缓冲(不缓冲意味着发送块将起作用)。
代理缓冲(基于标头和指令)已记录这里。
答案2
正如 Lukas 所暗示的,Content-Length
如果有Transfer-Encoding
集合,HTTP 1.1 就会禁止。
引用http://www.ietf.org/rfc/rfc2616.txt:
3.If a Content-Length header field (section 14.13) is present, its
decimal value in OCTETs represents both the entity-length and the
transfer-length. The Content-Length header field MUST NOT be sent
if these two lengths are different (i.e., if a Transfer-Encoding
header field is present). If a message is received with both a
Transfer-Encoding header field and a Content-Length header field,
the latter MUST be ignored.
答案3
您还没有具体阐述为什么您的脚本首先需要分块编码,尤其是在重定向响应中。
我发现这里存在很多问题。
Transfer-Encoding: chunked
是一个HTTP/1.1
功能(并且你的脚本似乎正在用HTTP/1.0
标题回复)没有
307
HTTP/1.0
的全部目的
chunked
是你不知道你的Content-Length
会是什么,所以,chunked
用来代替提供的长度Content-Length
,而是在响应主体中提供长度,与实际内容混合在一起;脚本预先生成两个标题是没有意义的
我个人并不熟悉chunked
,但根据http://en.wikipedia.org/wiki/Chunked_transfer_encoding并且https://www.rfc-editor.org/rfc/rfc2616#section-3.6.1,我猜测你的脚本对分块编码的整个处理可能是完全错误的。
如果上述内容仍未涵盖,而实际上并非如此,那么为什么带有307
或302
http 状态代码的回复应采用“奇怪”的编码也不清楚。最近,nginx 邮件列表中有一个类似的讨论,讨论410 Gone
和其他错误页面始终被排除在gzip
压缩之外,我认为这种观点在这里同样适用。(http://mailman.nginx.org/pipermail/nginx/2013-March/037890.html)
答案4
分享这个答案,我发布到SO,以防它有帮助:https://stackoverflow.com/questions/50499637/mp4-video-safari-cloudflare-nginx-rails-no-play/59348509#59348509
由于块未提供,我在播放 mp4 时也遇到了类似的问题,并根据下面列出的 Apple 指南确认了该问题。我确认我正在下载整个文件,但在下面的修复之后,只下载了第一个块。
curl --range 0-99 http://example.com/test.mov -o /dev/null
我通过更改 nginx.conf 中的 gzip 压缩设置解决了 Safari .mp4 播放问题,删除了.mp4文件。
以下是 nginx 中的块,供参考。(注意:根据应用程序的配置方式,您可能需要将位置行更改为location ~ \.mp4$ {
location ~ ^/(assets|system|videos)/ {
expires max;
add_header Cache-Control public;
add_header ETag "";
gzip on;
gzip_http_version 1.1;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
# Reference configuration
#gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript video/mp4 application/mp4 image/jpeg image/png image/svg+xml application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;
# Kelton trying to fix cloudflare by removing the mp4 settings
gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript image/jpeg image/png image/svg+xml application/application/x-font-ttf application/x-font-truetype application/font-woff application/font-woff2 application/vnd.ms-fontobject;
}