Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

nginx 配置之 proxy_pass 的 buffers

  我们经常会使用 proxy_pass 从另一台服务器获取数据并响应给客户端。大多数情况下,我们使用 proxy_pass 来转发的请求都是普通的请求,它们只在乎最终的结果,不在乎传输的过程。但如果是处理一些长连接,需要传输实时数据的情况,我们还需要考虑 buffers 的问题。
  为了最高效的传输,proxy_pass 默认是有开启 buffer 的。也就是说,nginx 从目标服务器拿到数据后并不会立即发送给客户端,而是放在 buffer 中,等到 buffer 满时才发送给客户端。这个设定对于大多数普通的资源型请求是有利的,它可以避免冗余的传输层数据包。但有时候,客户端的这个请求可能是一个基于数据流的长连接,如果 nginx 还把数据还放入 buffer 中就会造成数据无法实时传达的问题。
  nginx 当然也不是傻逼,在发明这个机制之前就考虑到了这个问题,所以我们可以通过配置 proxy_buffering 指令的值为 off,很容易地将 buffer 给关闭:
location / { proxy_pass http://127.0.0.1:8000; proxy_buffering off; }   假如我们有个这样的服务器程序,每 100 毫秒会响应一个字符 "x",总共 32 个:
const LENGTH = 32; require('http').createServer((req, res) => { res.writeHeader(200, { 'Content-Type': 'text/html', 'Content-Length': LENGTH }); void function callee(i) { if(i < LENGTH) { res.write('x'); setTimeout(callee, 100, i + 1); } else { res.end(); } }(0); }).listen(8000);   如果直接用浏览器访问这个 node 服务的端口 8000,会看到 "x" 是逐个出现的。一旦用 nginx 去 proxy_pass,并且没有设置 proxy_buffering,那么请求就会先陷入等待,然后所有的 "x" 再同时出现。只有将 proxy_buffering 设置为 off 之后才能得到和直接访问 node 服务端口一样的结果。
  并不是所有时候我们都改得了 nginx 配置的。假如 nginx 是别人家的,无法改配置怎么办?这也是有办法解决的!nginx 会识别一个叫 X-Accel-Buffering 的 HTTP 响应头,它的取值是 yes 和 no(注意不是 proxy_buffering 的 on 和 off)。所以我们在 node 代码中加入这个响应头就可以关闭掉 nginx 那一层 proxy_pass 的 proxy_buffering。而且 X-Accel-Buffering 的优先级比 nginx 配置中的 proxy_buffering 优先级更高,也就是说即使设置了 proxy_buffering 也会被 X-Accel-Buffering 给覆盖掉。
  中国有句老话叫道高一尺魔高一丈,nginx 这一层当然不能眼睁睁地把配置权限交给上游,它还可以通过 proxy_ignore_headers X-Accel-Buffering 的方式来忽略掉从上游服务器响应过来的特殊头对自己的影响。
  另外,对于 buffers 的具体配置,其实还有 proxy_buffersproxy_buffer_size 之类的配置项可以影响。然而我并没有玩到这么细的程度,只是知道它们是什么而已,于是就不继续装逼了。
网名:
50.16.97.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^