Tyrus websocket: IllegalStateException cannot set WriteListener for non-async request

前端 未结 1 587
隐瞒了意图╮
隐瞒了意图╮ 2020-12-07 05:40

I have a standard websocket endpoint based on Tyrus implementation which times to times triggers the java.lang.IllegalStateException: Cannot set WriteListener for non-

相关标签:
1条回答
  • 2020-12-07 05:56

    java.lang.IllegalStateException: Cannot set WriteListener for non-async or non-upgrade request

    In order for a request to be fully asynchronous, any Filter in the request-response chain must explicitly be set to support asynchronous requests. Specifically those "catch-all" filters which are mapped on /*.

    In case the filter is registered via <filter> entry in web.xml, this can be done by setting child element <async-supported> to true.

    <filter>
        ...
        <async-supported>true</async-supported>
    </filter>
    

    In case the filter is registered via @WebFilter annotation, this can be done by setting its asyncSupported attribute to true.

    @WebFilter(..., asyncSupported="true")
    

    In case the filter is registered via ServletContext#addFilter(), this can be done by setting Registration.Dynamic#setAsyncSupported(). to true.

    Dynamic filter = servletContext.addFilter(name, type);
    filter.setAsyncSupported(true);
    

    Reason is, the WebSocket implementation internally uses ServletRequest#startAsync() during the handshake request in order to keep the request-response pipeline "forever" open until the response is explicitly closed. Its javadoc says the following:

    Throws
    IllegalStateException - if this request is within the scope of a filter or servlet that does not support asynchronous operations (that is, isAsyncSupported() returns false), or if this method is called again without any asynchronous dispatch (resulting from one of the AsyncContext.dispatch() methods), is called outside the scope of any such dispatch, or is called again within the scope of the same dispatch, or if the response has already been closed

    The isAsyncSupported() defaults to false in order to not break existing web applications using poorly implemented servlet filters. Technically, it should suffice to mark only the target Servlet as async supported and leave the filters alone. A sane "catch-all" Filter wouldn't explicitly write anything to the HTTP response, but the Servlet API did never forbid that and thus such filters can unfortunately exist.

    In case you have one such filter, then you should either fix it to not write anything to the response anymore so that you can safely mark it to support async requests, or to adjust its URL pattern to not cover WebSocket requests. I.e. don't map it on /* anymore.

    0 讨论(0)
提交回复
热议问题