Kubernetes nginx ingress控制器返回502但仅适用于AJAX / XmlHttpRequest请求

时间:2016-10-27 15:56:43

标签: nginx kubernetes

我有一个在nginx入口控制器后面运行Kubernetes的Web应用程序,它适用于请求浏览,但是来自浏览器的任何AJAX / XMLHTTPRequest都会从nginx获得502错误。

我捕获常规和AJAX请求的HTTP标头,它们看起来很好,正确的主机标头,协议等。我很困惑为什么只有XMLHttpRequest请求从nginx获取502。没有延迟/挂起,502是立即的。请求似乎永远不会到达应用程序,但被nginx本身拒绝。将nginx切换为直接负载均衡器,问题就消失了。

我要进一步挖掘,但我想知道是否有其他人使用nginx入口控制器之前看到过这个问题并解决了它?

我从nginx日志中选择了这个错误,这表明容器返回一个响应,其中包含一个nginx缓冲区的标头太大。但是我检查了nginx.conf并且禁用了缓冲:'proxy_buffering off;'

2016/10/27 19:55:51 [error] 309#309: *43363 upstream sent too big header while reading response header from upstream, client: 10.20.51.1, server: foo.example.com, request: "GET /admin/pages/listview HTTP/2.0", upstream: "http://10.20.66.97:80/admin/pages/listview", host: "foo.example.com", referrer: "https://foo.example.com/admin/pages"

奇怪的是,只有在XmlHttpRequest请求URL时才会出现504错误。如果我使用curl请求相同的URL它工作正常,响应标头如下所示。那个相同URL的AJAX / XmlHttpRequest怎么会使响应头太大?

HTTP/1.1 200 OK
Server: nginx/1.11.3
Date: Thu, 27 Oct 2016 20:15:16 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6596
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
X-Powered-By: PHP/5.5.9-1ubuntu4.19
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: max-age=0, must-revalidate, no-transform, no-cache, no-store
Pragma: no-cache
X-Controller: CMSPagesController
X-Title: Example+Site+-+Pages
X-Frame-Options: SAMEORIGIN
Vary: X-Requested-With,Accept-Encoding,User-Agent
Strict-Transport-Security: max-age=15724800; includeSubDomains; preload

1 个答案:

答案 0 :(得分:5)

我解决了这个问题。只有XmlHttpRequests失败的原因是因为应用程序在看到XmlHttpRequest请求时有一个特殊的行为,它将大约3000字节的额外标头转储到响应中。这使得总标头大小大于默认的nginx标头缓冲区。

nginx阻塞大型HTTP头有效负载很常见,因为它的默认缓冲区大小比大多数其他Web服务器小,只有4k或8k。错误的解决方案是通过添加这些设置将标头使用的缓冲区增加到16k。

proxy_buffers         8 16k;  # Buffer pool = 8 buffers of 16k
proxy_buffer_size     16k;    # 16k of buffers from pool used for headers

nginx文档很模糊,这些设置含糊不清。据我所知,每个连接都有一个缓冲池。在这种情况下,每个16k的8个缓冲区。这些缓冲区用于从上游Web服务器接收数据并将数据传递回客户端。

所以proxy_buffers决定了游泳池。然后proxy_buffer_size确定主机的大部分缓冲池可用于从上游服务器接收HTTP头(我认为四舍五入到整个缓冲区大小)。第三个设置proxy_busy_buffer_size确定缓冲池可以忙于发送到客户端的数量(我认为四舍五入到整个缓冲区大小)。默认情况下,proxy_busy_buffer_size会自动设置为池中缓冲区数减1。

因此proxy_buffers池必须足够大以适应proxy_busy_buffer_size,并且仍然有足够的缓冲区以至少适合来自上游Web服务器的HTTP头的proxy_buffer_size。< / p>

净值是,如果你增加proxy_busy_buffer_size,你可能会立即得到令人困惑的错误:"proxy_busy_buffers_size" must be less than the size of all "proxy_buffers" minus one buffer,然后你必须增加池的大小。

你问的proxy_buffering off设置?好吧,这不会禁用代理缓冲!而是nginx是否会在将其发送到浏览器时缓冲到整个响应(缓冲池或磁盘),或者它是否只缓冲适合缓冲池的内容。因此即使你转off proxy_buffering代理缓冲仍然会发生。

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size

Maximum on http header values?

我看到了一堆关于设置大型缓冲池的建议,例如:大数字,如8 x 512kb缓冲区(= 4MB)。 每个连接都有一个缓冲池,因此保留缓冲池越小,您可以处理的连接就越多。