英文:
How to properly refuse websocket upgrade request?
问题
有时候我想拒绝一个HTTP客户端的升级连接到WebSocket的请求。
代码
(使用go
的Gin
和gorilla/websocket
框架:)
允许升级:
c, err := ctl.upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
err = c.WriteJSON(resp)
拒绝升级(由于无效的请求参数):
if contentId == "" || !exists {
// FIXME: 以一种WebSocket客户端可以识别和显示提示的方式提供响应?
ctx.String(http.StatusBadRequest, "invalid or non-existing contentId")
return
}
解释:在这里,我只需返回一个HTTP 400
状态码来拒绝升级,然后终止连接,根本不进行升级。
问题
使用上述代码拒绝WebSocket升级请求的问题在于,WebSocket客户端(例如js
)无法读取我响应中的数据(文本或JSON)。
客户端端代码(js
):
ws.onerror = function (evt) {
// 处理错误(例如打印错误消息?)
console.log("ERROR");
}
它确实在拒绝时打印了"ERROR"
,但在检查Chrome开发者工具中的evt
对象后,找不到获取服务器响应数据的方法,因此无法向前端UI显示拒绝的原因。
问题
- 如何正确拒绝WebSocket升级请求,并让客户端能够接收返回的原因/数据?(例如,客户端是
js
,服务器是go
/gin
/gorilla/websocket
)。 - 除了返回
400
这样的HTTP状态码,是否有更好的方式来拒绝WebSocket升级请求?
英文:
Sometimes I want to refuse a http client's request to upgrade connection to websocket.
Code
(using go
's Gin
and gorilla/websocket
framework:)
To allow upgrade:
c, err := ctl.upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
err = c.WriteJSON(resp)
To refuse upgrade (due to invalid request params):
if contentId == "" || !exists {
// FIXME: provide response in a way that ws client can recognize & show tip?
ctx.String(http.StatusBadRequest, "invalid or non-existing contentId")
return
}
Explaination: Here to refuse the upgrade I just return a http 400
code, then terminate the connection, and didn't do the upgrade at all.
The issue
The problem to refuse websocket upgrade request with about code is that, the websocket client (e.g js
), can't read data (text or json) in my response.
Code - client-side (js
):
ws.onerror = function (evt) {
// TOOD: handle error, (e.g print error msg?),
print("ERROR");
}
It does print the "ERROR"
on refuse, but after checking chrome developer tool about the evt
object, can't find a way to get server response data, so I can't show tip to frontend UI with reason of refuse.
Questions
- How to refuse websocket upgrade request properly, and let client be able to receive the returned reason/data ? (e.g client is
js
, server isgo
/gin
/gorilla/websocket
). - Is there a better way to refuse websocket upgrade request, other than return http code like
400
?
答案1
得分: 2
拒绝WebSocket连接时,不要按照问题中描述的方式升级连接。浏览器API不提供有关拒绝连接的原因的信息,因为该信息可能违反同源策略。
要将错误原因发送回客户端应用程序或用户,请执行以下操作:
- 升级连接。
- 发送带有错误原因的关闭消息。
- 关闭连接。
以下是一个示例:
c, err := ctl.upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
if err != nil {
// TODO: 处理错误
}
if contentId == "" || !exists {
c.WriteMessage(websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.ClosePolicyViolation,
"bad content id or not exist"))
c.Close()
return
}
// 在非错误情况下继续处理。
在JavaScript的关闭处理程序中访问关闭原因:
ws.onclose = function (evt) {
if (evt.code == 1008) { // 1008表示策略违规
console.log(evt.reason)
}
}
英文:
To reject a websocket connection, do not upgrade the connection as described in the question.
The browser API does not provide information about why the connection was rejected because the information can violate the same-origin policy.
Do the following to send an error reason back to the client application or user:
- Upgrade the connection.
- Send a close message with the error reason.
- Close the connection.
Here's an example:
c, err := ctl.upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
if err != nil {
// TODO: handle error
}
if contentId == "" || !exists {
c.WriteMessage(websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.ClosePolicyViolation,
"bad content id or not exist"))
c.Close()
return
}
// Continue with non-error case here.
Access the reason from the close handler in JS:
ws.onclose = function (evt) {
if (evt.code == 1008) { // 1008 is policy violation
console.log(evt.reason)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论