higress-gateway返回upstream_reset_before_response_started{protocol_error}

背景

问题表现是无法访问域名,页面打不开,

file

file

使用culr命令同样的报错:

file

解决

原来使用nginx的ingress,迁移到higress后,前端访问higress-gateway再调用后端服务,这个报错不是后端返回的,而是higress-gateway。查看higress-gateway的日志:

{...,"response_code":"502","response_flags":"UPE",...,"response_code_details":"upstream_reset_before_response_started{protocol_error}"}

搜索相关文档,找到一个:https://github.com/istio/istio/issues/24753 ,根据文档查看详细报错信息得修改日志级别为trace。修改higress-gateway的yaml:

file

将warning修改为trace。pod重启后,再次访问查看trace日志:

file

从中可以看到:

completed header: key=transfer-encoding value=chunked
Error dispatching received data: http/1.1 protocol error: both 'Content-Length' and 'Transfer-Encoding' are set.
upstream reset: reset reason: protocol error, transport failure reason
upstream_reset_before_response_started{protocol_error}
encoding headers via codec (end_stream=false): ':status', '502'

说明这是前端的http1.1请求,使用了keep-alive,并且同时设置了Content-LengthTransfer-Encoding: chunked导致。

这样就有两种解决方法:

方法一

修改代码,Content-LengthTransfer-Encoding: chunked二者选其一。

方法二

使用EnvoyFilter让envoy同时接受这两个header。参考:https://github.com/envoyproxy/envoy/issues/14004

vim envoyfilter.yaml

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: envoy-filter
  namespace: higress-system
spec:
  configPatches:
  - applyTo: CLUSTER
    match:
      context: ANY
    patch:
      operation: MERGE
      value:
        http_protocol_options:
          allow_chunked_length: true

k apply -f envoyfilter.yaml

再次访问,恢复正常。

问题1

为什么从nginx切换到higress就无法访问了?

查看之前的ingress-nginx的yaml,pod使用的镜像版本:nginx-ingress-controller:v1.3.1,进入容器查看nginx版本:

file

版本为1.19.10,是一个较低的版本。在高版本中nginx也遵循HTTP协议规范RFC。

问题2

为什么这两个header不能同时设置?

在HTTP协议中,keep-aliveContent-LengthTransfer-Encoding: chunked传输编码涉及到数据传输的方式和连接的保持。

  • Keep-Alive:是一种HTTP连接选项,用于保持连接在多个请求/响应对之间打开。启用keep-alive后,客户端和服务器可以复用同一个TCP连接,而不需要为每次请求都重新建立连接。
  • Content-Length:是HTTP响应头字段,用来指示响应体的字节长度。客户端通过Content-Length知道何时读取到完整的响应体,这在保持连接复用的场景中尤其重要。
  • Chunked Transfer-Encoding:当服务器无法在发送响应之前确定内容的长度时,使用Transfer-Encoding: chunked传输编码可以分块传输响应体。每个块都有自己的长度标识,客户端可以逐块接收数据,直到接收到长度为0的块,这标志着响应体的结束。

组合使用规则:

  • Content-LengthTransfer-Encoding: chunked不能同时使用:在同一个HTTP响应中,不能同时设置这两者。这是因为这两种方式都用来表示响应体的结束,若两者同时存在会造成混淆。

  • keep-alive可以与Content-LengthTransfer-Encoding: chunked配合使用:

    • 当使用keep-alive时,需要确保客户端能够准确地知道响应体的边界,以便继续使用同一连接发送后续请求。
    • 使用Content-Length时,客户端可以通过Content-Length头知道响应体的结束位置,便于继续保持连接。
    • 使用Transfer-Encoding: chunked编码时,客户端通过每个块的大小以及最后的零长度块来判断响应结束,支持keep-alive。

如何选择:

  1. 如果知道响应体的大小:使用Content-Length,这样可以在keep-aliv 模式下继续复用连接。
  2. 如果响应体大小不确定(例如,流式响应或动态生成的内容):使用Transfer-Encoding: chunked,这允许服务器边生成内容边传输,并仍然保持keep-alive连接。
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x