简体   繁体   中英

Fail to set up the connection with Atmosphere (2.2.4) in Android(4.1 ~ 4.3) (Websocket with Long-Polling as fallback)

The connection can't be set up at all for real time pushing. But Android(4.4+) will be no issue at all.

The following is the error message reported by the Atmosphere.

Invalid request state. AsyncContext#startAsync not supported. Make sure async-supported is set to true in web.xml

The reasons are

  1. Android browser websocket support start from 4.4

  2. Android browser 4.1 seems have some issue to support the CROS request refer to How do I send a cross-domain POST request via JavaScript? . Must remember few things,

    a. Set the Atmosphere javascript long-poll option allowCredentials to true, if using session

    b. disable the atmosphere buildin CROS headers through "dropAccessControlAllowOriginHeader" if using the jetty "CrossOriginFilter".

  3. Android (4.1+) webview can use the setAllowUniversalAccessFromFileURLs(true) to tackle the CROS issue

  4. Atmosphere's AtmosphereServlet(2.2.4) doOptions() need be overwritten as the following. In the web.xml, use this new child class instead of the original AtmosphereServlet class to handle the request

     public void doOptions(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { res.setHeader("Allow", "GET,HEAD,POST"); } 

Once the above is done, the android Atmosphere connection will be up for 4.1~4.3.

If the host is the Jetty (9.2+), there is another issue, that the "isAsyncSupported()" check in "AsynchronousProcessor" is always false. And this will cause the following error message

 if (isServlet30 && (!req.isAsyncSupported() && !Utils.closeMessage(req)))

In Jetty (9.2+) ServletHandler class, the following code's comments tell you why the req.isAsyncSupported() become false!!! In my case, it is because of google guice filter. it is not async enabled.

            //if the request already does not support async, then the setting for the filter
            //is irrelevant. However if the request supports async but this filter does not
            //temporarily turn it off for the execution of the filter
            boolean requestAsyncSupported = baseRequest.isAsyncSupported();
            try
            {
                if (!_filterHolder.isAsyncSupported() && requestAsyncSupported)
                    baseRequest.setAsyncSupported(false);
                filter.doFilter(request, response, _next);
            }
            finally
            {
                baseRequest.setAsyncSupported(requestAsyncSupported);
            }
            return;

To address this, just simply add the "async-supported" into the web.xml for each configured filter.

    <filter-name>guiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    <async-supported>true</async-supported>

    <filter-name>cross-origin</filter-name>
    <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
    <async-supported>true</async-supported>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM