我需要能够在握手期间中止websocket连接,以防HTTP请求不符合某些条件。根据我的理解,正确的地方是我自己Configurator
实现的ServerEndpointConfig.Configurator.modifyHandshake()方法。我只是无法弄清楚要做什么来中止连接。有一个HandshakeResponse参数允许在响应中添加标题,但我找不到任何标题来完成这项工作。
那么如何在握手期间中止websocket连接?这甚至可能吗?
答案 0 :(得分:3)
你是对的,使用'modifyHandShake()'更新响应标题,你需要删除或设置标题Sec-WebSocket-Accept
的值,从the spec
| Sec-WebSocket-Accept |标题字段表示是否 服务器愿意接受连接。如果存在,这个 标头字段必须包含发送的客户端随机数的哈希值 |仲WebSocket的密钥|以及预定义的GUID。任何其他价值 不得被解释为接受连接 服务器
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
这些字段由WebSocket客户端检查脚本页面。 如果是| Sec-WebSocket-Accept |值与预期值不匹配 值,如果缺少标头字段,或者HTTP状态代码是否为 不是101,连接将不会建立,而WebSocket框架 将不会被发送。
您的代码如下所示:
@Override
public void modifyHandshake(ServerEndpointConfig sec,
HandshakeRequest request, HandshakeResponse response) {
super.modifyHandshake(sec, request, response);
response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, new ArrayList<String>());
}
浏览器会将此解释为服务器未接受连接。例如在chrome中我收到消息
Websocket握手期间出错
答案 1 :(得分:2)
我知道 - 旧帖子但我没有看到任何改进。所以也许有人可以讨论我解决这个问题的方法。
我试过leos版本,运行Wildfly 8.0,Undertow 1.0
final ArrayList<String> finalEmpty = new ArrayList<String>();
response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT,finalEmpty);
这会引起一些有趣的行为:
即使您的浏览器应该关闭连接,它们也都会通过onOpen()
程序。
onOpen()
,然后触发onError()
。在我的
case,我做一些关于断开连接的客户端的日志记录,所以我一直打电话
发生错误时onClose()
。不要弄乱你的标题,也不要让客户做好工作。
相反,您应该向配置添加身份验证数据。
/** some verification foo code...**/
config.getUserProperties().put("isValid",true);
然后在onOpen()
中检查isValid的值。如果不是,请致电onClose(session,null);
。会议将结束。
它不是最好的解决方案,但那是因为websocket认证很糟糕,而且每个浏览器有时会表现不同。请参阅:Websocket: Closing browser triggers onError() in chrome but onClose() event in Firefox
答案 2 :(得分:2)
最简单的方法是在web.xml中设置简单的web过滤器,这将在握手之前执行。
Smth喜欢:
public class MyHandshakeFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
// do nothing
}
/**
* Passes request to chain when request port is equal to specified in the allowedPort property
* and returns HttpServletResponse.SC_NOT_FOUND in other case.
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
if (<your validation here based on http request>) {
// request conditions are met. continue handshake...
chain.doFilter(request, response);
} else {
// request conditions are NOT met. reject handshake...
((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
}
并在web.xml中:
<filter>
<filter-name>yourHandshakeFilter</filter-name>
<filter-class>com....MyHandshakeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>yourHandshakeFilter</filter-name>
<url-pattern>/yourEndpointUrl</url-pattern>
</filter-mapping>
并且您的ServerEndpoint应该像:
@ServerEndpoint("/yourEndpointUrl")
public class MyServerEndpoint {
...
}
答案 3 :(得分:1)
另一种技巧:
当您从ServerEndpointConfig.Configurator#modifyHandshake
抛出RuntimeException时,则表明连接未建立。
这适用于Tomcat 8.从Jetty example得到了这个想法,所以我猜它也适用于Jetty。