nginx - 通过 Ingress nginx 的独立 WebSocket 客户端失败
问题描述
在 Hosted Rancher Kubernetes 集群中,我有一个公开 websocket 服务(Spring SockJS 服务器)的服务。由于入口规则,此服务暴露在外部:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myIngress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600s"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600s"
nginx.ingress.kubernetes.io/enable-access-log: "true"
spec:
rules:
- http:
paths:
- path: /app1/mySvc/
backend:
serviceName: mySvc
servicePort: 80
Web 应用程序通过入口 nginx 连接到 Web 套接字服务,并且工作正常。加载的js脚本为:
var socket = new SockJS('ws');
stompClient = Stomp.over(socket);
stompClient.connect({}, onConnected, onError);
相反,独立客户端(js 或 python)不起作用,因为它们返回 400 http 错误。
例如,这是 curl 发送的请求和 nginx 的响应:
curl --noproxy '*' --include \
--no-buffer \
-Lk \
--header "Sec-WebSocket-Key: l3ApADGCNFGSyFbo63yI1A==" \
--header "Sec-WebSocket-Version: 13" \
--header "Host: ingressHost" \
--header "Origin: ingressHost" \
--header "Connection: keep-alive, Upgrade" \
--header "Upgrade: websocket" \
--header "Sec-WebSocket-Extensions: permessage-deflate" \
--header "Sec-WebSocket-Protocol: v10.stomp, v11.stomp, v12.stomp" \
--header "Access-Control-Allow-Credentials: true" \
https://ingressHost/app1/mySvc/ws/websocket
HTTP/2 400
date: Wed, 20 Nov 2019 14:37:36 GMT
content-length: 34
vary: Origin
vary: Access-Control-Request-Method
vary: Access-Control-Request-Headers
access-control-allow-origin: ingressHost
access-control-allow-credentials: true
set-cookie: JSESSIONID=D0BC1540775544E34FFABA17D14C8898; Path=/; HttpOnly
strict-transport-security: max-age=15724800; includeSubDomains
Can "Upgrade" only to "WebSocket".
为什么它适用于浏览器而不是独立客户端?
谢谢
解决方案
我在 Spring 应用程序中激活了跟踪,并使用 curl 调用:
o.s.w.s.s.s.DefaultHandshakeHandler : Handshake failed due to invalid Upgrade header: null
因此,似乎 nginx 删除了 Upgrade 标头!
使用浏览器客户端进行测试时,标头存在于 Spring Applicaton 中并且可以正常工作。
推荐阅读
- java - 如何将弹性 4j 速率限制在内存阈值之上?
- docker - 复制失败:没有这样的文件或目录
- blockchain - 权益证明:哪个节点选择下一个区块验证者?
- laravel - 一小时间隔 - Laravel
- r - c50 代码名为 exit,值为 1 AND 错误:C5.0 模型需要一个因子结果
- oracle - 是否可以在其他 docker 容器中重用 oracle 数据库文件(.dbf)
- php - 错误:不能使用 Symfony\Component\HttpFoundation\Request 类型的对象作为数组
- android - 三星设备在 Android 11 中的 is_pending 更新崩溃
- python - 为什么 MySQL 将 acuñar 注册为 acunar 的重复条目?
- java - 如何使用 java restTeplate 将原始数据添加到正文请求