3

In the servlet world there would be things like cookies and HttpSession for me to identify who was hitting my restful service to route the request to the correct data. Is it a good idea to use the Sec-WebSocket-Key as though it is a cookie identifying the client connection?

Specifically I am using the socko scala library (an akka webserver based on netty) to implement a websocket server starting from the demo app at socko-examples. Socko is wrapping a netty Channel and passing a netty WebSocketFrame into the application code. I would then like to dispatch the frame of incoming data based on "some identity" for the client connection which I have previously associated to the end users data (e.g their shopping basket). To do this I have written extension methods to expose the Sec-WebSocket-Key http header as though it is a top level property of the objects which come into the application by digging out the http header from the original websocket handshake:

package org.mashupbots.socko.examples.websocket

// pimp my library pattern to add extension method
object ChatWebSocketExtensions {
  import org.mashupbots.socko.events.WebSocketFrameEvent

  class WebSocketFrameEventWithSecWebSocketKey(wsFrame: WebSocketFrameEvent) {
    def secWebSocketKey: String = { 
      wsFrame.initialHttpRequest.headers.get("Sec-WebSocket-Key").getOrElse("null") 
    }
  }
  implicit def webSocketFrameEventWithSecWebSocketKey(wsFrame: WebSocketFrameEvent) = new WebSocketFrameEventWithSecWebSocketKey(wsFrame)

  import org.mashupbots.socko.events.WebSocketHandshakeEvent;

  class WebSocketHandshakeEventWithSecWebSocketKey(event: WebSocketHandshakeEvent) {
    def secWebSocketKey: String = {
      val option = Option(event.nettyHttpRequest.getHeader("Sec-WebSocket-Key"))
      return option.getOrElse("null");

    }
  }
  implicit def webSocketHandshakeEventWithSecWebSocketKey(event: WebSocketHandshakeEvent) = new WebSocketHandshakeEventWithSecWebSocketKey(event)

}

Thats only some syntactic sugar so that the app code does not have to go digging around in the low level objects to get the Sec-WebSocket-Key header and just access it as though it were a first class property:

  val routes = Routes({
    case WebSocketHandshake(wsHandshake) => wsHandshake match {
      case GET(PathSegments("websocket" :: roomNumber :: Nil)) => {
        log.info("Handsake to join room " + roomNumber)
        wsHandshake.authorize(onComplete = Some((event: WebSocketHandshakeEvent) => {
          val identity = event.secWebSocketKey;
          log.info("Authorised connection:" + identity);
          // do something with this identified user connection
        }))
      }
    }

    case WebSocketFrame(wsFrame) => {
      // Once handshaking has taken place, we can now process frames sent from the client
      val identity = wsFrame.secWebSocketKey;
      log.info("chat from:" + identity);
      // do something with this identified data frame
    }

  })

My question is whether this is good practice or is there a better way to identify the user connection?

4

1 回答 1

6

'Sec-WebSocket-Key' 标识一个连接。

但是,我不太确定使用“Sec-WebSocket-Key”是否是识别“会话”的好主意。

这是因为 'Sec-WebSocket-Key' 不适应断开连接并要求客户端建立新连接的情况。可能会发布一个新的“Sec-WebSocket-Key”。用户将失去他/她的会话。

使用 HTTP,会话通常与 URL 中的 cookie 或 id 相关联——这两者都独立于 HTTP 连接。这样,多个 HTTP 连接可以用于单个用户会话。

我建议你为你的网络套接字“会话”使用类似的东西。

作为握手和成功登录的一部分,让服务器向客户端发送会话 ID。客户端应随每个请求将会话 ID 发送回服务器。

这样,您可以使用https://github.com/joewalnes/reconnecting-websocket之类的 javascript在您的应用程序代码中提供网络弹性。

希望这可以帮助。

于 2013-09-24T22:30:42.447 回答