我有一个Go服务作为Heroku上的Web套接字服务器。客户端每20秒ping一次服务器,似乎保持连接打开。问题是当套接字连接关闭时,Heroku路由器抛出H15错误,认为请求花费了太多时间。例如,如果Web套接字连接已打开300秒,Heroku日志将显示:
... ... .H15。 dyno = web.1 connect = 1ms service = 300000ms status = 503 bytes = 147 ....
有人经历过这个吗?
答案 0 :(得分:4)
是的!我经历了这种情况,经过一些深入的调试,我得出的结论是,这只是Heroku Router引擎中的“假阳性”。我的调试过程如下:
service=79859ms status=101
结论:只要您的客户端应用终止WebSocket连接,Heroku Router就会记录一条错误15行,该连接在X毫秒的时间内运行良好。因此,在许多情况下,可能只是用户离开了您的应用。
我希望这对人们有帮助,希望你们可以少担心一件事情:)
答案 1 :(得分:2)
我通过每秒从服务器发送ping来解决问题,如heroku nodejs示例:https://github.com/heroku-examples/node-websockets/blob/master/server.js
答案 2 :(得分:0)
如果有人来这里从Java
的角度寻找解决方案:
@Component
public class SocketHandler extends TextWebSocketHandler {
public static Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String userName = (String) session.getAttributes().get("userName");
sessions.put(userName, session);
super.afterConnectionEstablished(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
String userName = (String) session.getAttributes().get("userName");
sessions.remove(userName);
super.afterConnectionClosed(session, status);
}
}
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/webSocket/AppName/*").addInterceptors(auctionInterceptor());;
}
@Bean
public HandshakeInterceptor auctionInterceptor() {
return new HandshakeInterceptor() {
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
// Get the URI segment corresponding to the auction id during handshake
String path = request.getURI().getPath();
String userName = path.substring(path.lastIndexOf('/') + 1);
// This will be added to the websocket session
attributes.put("userName", userName);
return true;
}
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception exception) {
// Nothing to do after handshake
}
};
}
}
以上是我在Spring引导中的WebSocket配置,因为我只希望创建连接并将其保持在map
中,并带有用户名和会话详细信息。
之后,在Springboot中,主方法仅每30秒添加一次ping,如下所示:
public static void main(String[] args) {
SpringApplication.run(MayAppName.class, args);
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable r = () -> {
if(SocketHandler.sessions != null && !SocketHandler.sessions.isEmpty()) {
for (Map.Entry<String, WebSocketSession> stringWebSocketSessionEntry : SocketHandler.sessions.entrySet()) {
try {
// Dummy ping to keep connection alive.
stringWebSocketSessionEntry.getValue().sendMessage(new TextMessage("Dummy Ping"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
scheduler.scheduleAtFixedRate(r, 0, 30, TimeUnit.SECONDS);
}
这是什么,它会每30秒对用户进行一次ping操作,以使默认55
秒不会影响websocket连接,如Heroku文档中所建议的那样。
Timeouts
The normal Heroku HTTP routing timeout rules apply to WebSocket connections. Either client or server can prevent the connection from idling by sending an occasional ping packet over the connection.
答案 3 :(得分:0)
在尝试发送之前检查 yourSocket.READYSTATE === WebSocket.OPEN
。
如果没有打开,那么通过实现类似 this
的东西来确保它是打开的仅仅实施乒乓解决方案不足以保持我的连接畅通。