IIS ARR未传递查询参数至PHP Ratchet WebSocket服务器问题求助
环境
通过ARR配置在IIS后方的PHP Ratchet WebSocket服务器,ARR用于将WebSocket请求转发至监听8080端口的服务器。
问题
通过wss://example.com/ntfs建立的WebSocket连接无法接收session_info等预期查询参数,导致400 Bad Request错误。直接访问ws://localhost:8080/ntfs?session_info可正常工作,但远程连接因该错误失败。ntfs目录下的IIS重写规则已设置为将请求转发至8080端口并附加查询字符串,但参数未被正确传递,引发400错误。
日志/诊断
已执行IIS失败请求跟踪,发现在重写模块处理阶段出现400 Bad Request错误。跟踪日志显示重写规则已触发,但查询参数似乎未正确传递。
补充信息
失败跟踪日志关键部分
GENERAL_REQUEST_START:
- SiteId: [已脱敏]
- AppPoolId: [DefaultAppPool]
- ConnId: [已脱敏]
- RequestURL:
https://[example.com]/ntfs?session_info=%7B%22TLUserID%22%3A[UserID]%2C%22username%22%3A[Username]%2C%22groups%22%3A%5B%22GroupID%22%5D%7D - RequestVerb: GET
RULE_EVALUATION_START:
- RuleName: WebSocketProxy
- QueryString:
session_info=%7B%22TLUserID%22%3A[UserID]%2C%22username%22%3A[Username]%2C%22groups%22%3A%5B%22GroupID%22%5D%7D - PatternSyntax: Regex
- StopProcessing: true
- RelativePath: /ntfs/
RULE_EVALUATION_END:
- RuleName: WebSocketProxy
- RequestURL:
http://[example.com]:8080 - QueryString:
?session_info=%7B%22TLUserID%22%3A[UserID]%2C%22username%22%3A[Username]%2C%22groups%22%3A%5B%22GroupID%22%5D%7D - StopProcessing: true
- Succeeded: true
URL_CHANGED:
- OldUrl:
/ntfs?session_info=%7B%22TLUserID%22%3A[UserID]%2C%22username%22%3A[Username]%2C%22groups%22%3A%5B%22GroupID%22%5D%7D - NewUrl:
http://[example.com]:8080?session_info=%7B%22TLUserID%22%3A[UserID]%2C%22username%22%3A[Username]%2C%22groups%22%3A%5B%22GroupID%22%5D%7D
- OldUrl:
MODULE_SET_RESPONSE_ERROR_STATUS:
- ModuleName: ApplicationRequestRouting
- Notification: EXECUTE_REQUEST_HANDLER
- HttpStatus: 400
- HttpReason: Bad Request
- ErrorCode: 操作已成功完成 (0x0)
GENERAL_SET_REQUEST_HEADER:
- HeaderName: AspFilterSessionId
- HeaderValue: [空]
- Replace: true
GENERAL_REQUEST_END:
- BytesSent: 557
- BytesReceived: 600
- HttpStatus: 400
- HttpSubStatus: 0
当前重写规则
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <rewrite> <rules> <rule name="WebSocketProxy" enabled="true" stopProcessing="true"> <match url="(.*)" /> <action type="Rewrite" url="http://example.com:8080" logRewrittenUrl="true" /> </rule> </rules> </rewrite> </system.webServer> </configuration>
问题根源及解决方案
从跟踪日志能看到两个核心问题:
- 重写后的URL丢失了原请求中的
/ntfs路径,而Ratchet服务器依赖这个路径匹配路由(直接访问ws://localhost:8080/ntfs?xxx正常,说明路径是必须的)。 - 虽然查询参数被附加到新URL,但ARR转发WebSocket请求时,默认可能无法正确处理参数传递,加上路径丢失,导致Ratchet服务器无法识别请求,返回400错误。
修正后的重写规则
修改规则以保留原请求的路径和查询参数:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <rewrite> <rules> <rule name="WebSocketProxy" enabled="true" stopProcessing="true"> <match url="(.*)" /> <action type="Rewrite" url="http://example.com:8080/{R:1}" logRewrittenUrl="true" /> </rule> </rules> </rewrite> </system.webServer> </configuration>
注:{R:1}会匹配原URL的路径部分(即ntfs),IIS重写模块默认会自动传递查询参数,无需额外配置条件。
额外配置检查
- 启用ARR的WebSocket代理:
- 打开IIS管理器,进入服务器节点的Application Request Routing Cache
- 点击Server Proxy Settings,勾选Enable proxy和Enable WebSocket proxy support
- 安装IIS的WebSocket功能:
- 通过服务器管理器添加Web Server (IIS)角色下的WebSocket Protocol组件
- 重启IIS站点,确保规则生效。
验证修改
重新发起wss://example.com/ntfs?session_info=xxx请求,查看失败请求跟踪日志,确认重写后的URL为http://example.com:8080/ntfs?session_info=xxx,此时Ratchet服务器应能正确接收路径和参数,返回正常响应。
内容的提问来源于stack exchange,提问作者CaptainJackSparrow

