Python WebSocket客户端wss连接报403 Forbidden错误问题
问题现象
- Python客户端基于
websocket库连接Azure托管的WebSocket服务,已正确传入认证请求头,使用wss://开头的URL连接时失败,返回错误:
Handshake status 403 Forbidden
- 完全相同的请求配置在Postman中测试可正常连接
- 仅当关闭Azure App Service的
HTTPSOnly配置项、改用ws://开头的非加密地址发起连接时,Python客户端可正常连通 - 对比Postman与Python客户端的请求头未发现差异,无法定位403错误根因
出问题的原始代码片段:
def on_message(ws, message): print(message) def on_error(ws, error): print(error) def on_close(ws, close_status_code, close_msg): print("### closed ###") def on_open(ws): print("Opened connection") auth_str = "Authorization:Basic abgvrgfrbnfrfurfr" if __name__ == "__main__": websocket.enableTrace(True) ws = websocket.WebSocketApp("wss://uri.com/websocket", header=[auth_str], on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close ) ws.run_forever(dispatcher=rel) rel.signal(2, rel.abort) rel.dispatch()
根因定位
该问题由两个常见因素叠加导致:
- 低版本
websocket-client库(<1.0.0)发起wss://加密连接时,默认不会在TLS握手中携带SNI(服务器名称指示)扩展。Azure App Service是多租户托管环境,依赖SNI值匹配对应站点,SNI缺失时请求会被路由到默认空站点,直接返回403。非加密的ws://连接不走TLS握手,不存在该问题。 websocket库发起WebSocket握手时,如果没有显式指定Origin头,会自动生成http://<域名>格式的Origin值。Azure App Service开启HTTPSOnly后会强制校验Origin协议,非HTTPS的Origin会被CORS规则直接拦截返回403;Postman发起请求时默认携带的Origin符合Azure校验规则,因此可以正常连通。
修复方案
按顺序执行以下操作即可解决问题:
- 升级websocket-client库到最新版本,修复SNI携带问题:
pip install --upgrade websocket-client
- 在WebSocket请求头中显式添加HTTPS协议的Origin头,匹配Azure的CORS校验规则,修正后的初始化代码如下:
if __name__ == "__main__": websocket.enableTrace(True) ws = websocket.WebSocketApp("wss://uri.com/websocket", header=[ auth_str, "Origin: https://uri.com" ], on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close ) ws.run_forever(dispatcher=rel) rel.signal(2, rel.abort) rel.dispatch()
- 如果调整后仍返回403,检查Azure App Service的CORS配置,确认请求Origin在允许列表中,可临时开启"允许所有来源"测试连通性。
补充:如果开启了ARR亲和性(Azure默认开启),首次连接前先发起一次HTTPS GET请求获取站点下发的ARR亲和性Cookie,将Cookie一并加入WebSocket请求头即可避免路由层拦截。
内容的提问来源于stack exchange,提问作者Mr. code
相关产品推荐
相关产品推荐

