Docker Openresty代理Apache Zeppelin时WebSocket报405错误求解决方案
解决OpenResty代理Apache Zeppelin时WebSocket 405错误的方案
我来帮你搞定这个WebSocket 405错误的问题,结合你提供的配置文件,主要有几个关键的调整点,咱们一步步来:
1. 先排查核心配置问题
405错误通常意味着请求方法不被允许,在WebSocket场景下,大多是握手阶段的请求没被正确代理,或者路径映射、头信息配置出了问题。咱们先从配置的几个关键部分入手:
修正Server名称与重定向逻辑
你的配置里server_name localhost:8080;是错误的——server_name只需要填域名/主机名,端口是在listen指令里定义的。同时重定向用$server_name可能导致端口错误,改成$host更可靠,因为它会读取请求的Host头:
server { listen 80; server_name localhost; # 改成你的实际域名或localhost if ($http_x_forwarded_proto = 'http') { return 301 https://$host$request_uri; # 用$host替代$server_name } # ... 其他配置 }
添加WebSocket升级的动态映射
WebSocket握手需要正确处理Upgrade和Connection头,固定写"upgrade"可能无法兼容所有客户端的请求格式,建议在http块里添加一个映射规则:
http { # ... 其他已有配置 map $http_upgrade $connection_upgrade { default upgrade; '' close; } # ... 其他已有配置 }
修正WebSocket的Location配置
你的location /zeppelin/ws配置有几个需要调整的地方:
- 确保环境变量
ZEPPELIN_WEBSOCKET_URL的值是Zeppelin的基础地址(比如http://zeppelin-container:8080,不要加/ws后缀) - 通过重写规则去掉
/zeppelin前缀,确保请求能正确映射到Zeppelin的/ws端点 - 用上面定义的
$connection_upgrade变量替代固定的"upgrade" - 允许OPTIONS请求(WebSocket握手前会先发OPTIONS请求,避免被拦截)
修改后的WebSocket Location配置如下:
location ~^ /zeppelin/ws(.*) { # 去掉/zeppelin前缀,把请求映射到Zeppelin的/ws路径 rewrite ^/zeppelin(.*)$ $1 break; proxy_pass $ZEPPELIN_WEBSOCKET_URL; proxy_pass_header Sec-Websocket-Extensions; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # 使用动态映射的变量 proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_read_timeout 86400; # 允许OPTIONS请求,避免握手被拦截 if ($request_method = OPTIONS) { return 204; } }
检查环境变量是否正确
确认ZEPPELIN_WEB_URL和ZEPPELIN_WEBSOCKET_URL这两个环境变量已经正确设置:
ZEPPELIN_WEB_URL应该是Zeppelin的Web界面地址,比如http://zeppelin-container:8080/(注意结尾的斜杠,确保路径映射正确)ZEPPELIN_WEBSOCKET_URL是Zeppelin的基础地址,比如http://zeppelin-container:8080(不要加/ws)
2. 验证修改后的完整配置
把所有调整整合后,你的nginx.conf大概是这样的:
worker_processes 1; error_log /dev/stderr warn; events { worker_connections 1024; } env JWT_SECRET; http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /dev/stdout main; lua_package_path "/usr/local/openresty/lualib/?.lua;;"; gzip on; gzip_min_length 1; # 添加WebSocket升级映射 map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name localhost; if ($http_x_forwarded_proto = 'http') { return 301 https://$host$request_uri; } location /zeppelin/ { proxy_pass $ZEPPELIN_WEB_URL; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_redirect off; } location ~^ /zeppelin/ws(.*) { rewrite ^/zeppelin(.*)$ $1 break; proxy_pass $ZEPPELIN_WEBSOCKET_URL; proxy_pass_header Sec-Websocket-Extensions; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_read_timeout 86400; if ($request_method = OPTIONS) { return 204; } } location / { access_by_lua_file /bearer.lua; default_type text/html; proxy_pass $PROXY_SERVER_NAME; proxy_set_header Accept-Encoding ""; header_filter_by_lua_block { ngx.header.content_length = nil } body_filter_by_lua_block { if (ngx.req.get_headers()["Origin"] ~= nil) then local response_body = ngx.arg[1] local string_to_search = "</body>" local replacement_string = "<script>document.domain = \"" .. ngx.req.get_headers()["Origin"] .. "\";</script></body>" ngx.arg[1] = ngx.re.sub(ngx.arg[1], "</body>", replacement_string) end return ngx.arg[1] } } } }
3. 测试验证
修改配置后,重启OpenResty容器,然后:
- 访问Zeppelin的Web界面(通过OpenResty的
/zeppelin路径) - 打开浏览器开发者工具,切换到Network标签,过滤WebSocket请求
- 检查WebSocket连接是否成功建立,没有405错误
如果还是有问题,可以查看OpenResty的日志(docker logs <openresty-container>),看看具体的请求路径和错误信息,进一步排查。
内容的提问来源于stack exchange,提问作者Sanket Tarun Shah
相关产品推荐
相关产品推荐

