如何通过WebSockets正确向客户端报告错误

Sat*_*rn5 7 java java-websocket javax

当我的服务器发生内部错误时,如何正确关闭 websocket 并向客户端提供干净、信息丰富的响应?在我当前的情况下,客户端在连接时必须提供一个参数,并且我正在尝试处理 OnOpen 收到的不正确或丢失的参数。

这个例子表明我可以在 OnOpen 中抛出一个异常,它最终会调用 OnError ,我可以在其中给出原因和消息来关闭。它有点工作,但客户端只收到 EOF、1006、CLOSE_ABNORMAL。

另外,因为我没有找到其他讨论,所以我无法说出什么可能是最佳实践。

我正在使用 JSR-356 规范,如下所示:

@ClientEndpoint
@ServerEndpoint(value="/ws/events/")
public class WebSocketEvents
{
    private javax.websocket.Session session;
    private long token;

    @OnOpen
    public void onWebSocketConnect(javax.websocket.Session session) throws BadRequestException
    {
        logger.info("WebSocket connection attempt: " + session);
        this.session = session;
        // this throws BadRequestException if null or invalid long
        // with short detail message, e.g., "Missing parameter: token"
        token = HTTP.getRequiredLongParameter(session, "token");
    }

    @OnMessage
    public void onWebSocketText(String message)
    {
        logger.info("Received text message: " + message);
    }

    @OnClose
    public void onWebSocketClose(CloseReason reason)
    {
        logger.info("WebSocket Closed: " + reason);
    }

    @OnError
    public void onWebSocketError(Throwable t)
    {
        logger.info("WebSocket Error: ");

        logger.debug(t, t);
        if (!session.isOpen())
        {
            logger.info("Throwable in closed websocket:" + t, t);
            return;
        }

        CloseCode reason = t instanceof BadRequestException ? CloseReason.CloseCodes.PROTOCOL_ERROR : CloseReason.CloseCodes.UNEXPECTED_CONDITION;
        try
        {
            session.close(new CloseReason(reason, t.getMessage()));
        }
        catch (IOException e)
        {
            logger.warn(e, e);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:每个链接示例抛出的异常看起来很奇怪,所以现在我在 OnOpen 中捕获异常并立即执行

session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "some text")); 
Run Code Online (Sandbox Code Playgroud)

编辑:事实证明这是正确的,尽管一个单独的错误掩盖了它一段时间。


Edit2:澄清:HTTP是我自己的静态实用程序类。HTTP.getRequiredLongParameter()通过使用从客户端的初始请求获取查询参数

session.getRequestParameterMap().get(name)
Run Code Online (Sandbox Code Playgroud)

并进行进一步处理。

Sat*_*rn5 1

我相信我应该放置...

session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "some text"));
Run Code Online (Sandbox Code Playgroud)

...就在@OnOpen() 内发生错误的地方。(对于一般错误,请使用CloseCodes.UNEXPECTED_CONDITION。)

客户端收到:

onClose(1003, some text)
Run Code Online (Sandbox Code Playgroud)

当然,这是显而易见的答案。我认为我被引用的示例误导,从 @OnOpen() 抛出异常。正如Remy Lebeau所建议的,套接字可能因此被关闭,从而阻止我在 @OnError() 中进行任何进一步的处理。(其他一些错误可能掩盖了所讨论的证据。)