如何正确拒绝 WebSocket 升级请求?

huangapple go评论88阅读模式
英文:

How to properly refuse websocket upgrade request?

问题

有时候我想拒绝一个HTTP客户端的升级连接到WebSocket的请求。


代码

(使用goGingorilla/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 is go / gin / gorilla/websocket).
  • Is there a better way to refuse websocket upgrade request, other than return http code like 400?

答案1

得分: 2

拒绝WebSocket连接时,不要按照问题中描述的方式升级连接。浏览器API不提供有关拒绝连接的原因的信息,因为该信息可能违反同源策略

要将错误原因发送回客户端应用程序或用户,请执行以下操作:

  1. 升级连接。
  2. 发送带有错误原因的关闭消息。
  3. 关闭连接。

以下是一个示例:

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:

  1. Upgrade the connection.
  2. Send a close message with the error reason.
  3. 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)
    }
}

huangapple
  • 本文由 发表于 2022年2月12日 23:33:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/71093260.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定