1

我目前正在尝试配置一个 REST 应用程序,以使服务器端事件能够使用EventSource. 目前,我IllegalStateException在尝试打开与 REST 请求的异步连接时遇到了问题,这似乎是服务器未配置为允许异步请求的结果。

一些代码

@RequireBootstrapWebResource(resource="css/bootstrap.css")
@RequireWebServerExtender
@RequireHttpImplementation
@RequireConfigurerExtender
@Component(name="my.web", property={"debug=true"})
public final class MyApplication implements REST
{
   public void getBatching(RESTRequest request)
   {
      User user = authenticate(request);

      HttpServletResponse response = request._response();
      response.setStatus(HttpServletResponse.SC_OK);
      response.setContentType("text/event-stream");
      response.setCharacterEncoding(StandardCharsets.UTF_8.name());
      try
      {
         AsyncContext async = (AsyncContext)request._request().startAsync();
         async.addListener(new InternalAsyncListener());
         sseConnectionMap.put(UUID.randomUUID(), async);

         response.flushBuffer();
      }
      catch (Exception e)
      {
         System.out.println("Message=" + e.getMessage());
         e.printStackTrace();
      }
   }

   @SuppressWarnings("unused")
   @Activate
   void activate(ComponentContext cc, BundleContext bc, Map<String, Object> config)
   {
      System.out.println(this.getClass() + " started");

      if ("true".equals(config.get("debug")))
      {
         debug = true;
      }

      System.out.println("Link Start");
   }
}

目前打印以下内容:

Message=null
java.lang.IllegalStateException
at org.apache.felix.http.base.internal.dispatch.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:314)
at my.application.MyApplication.getBatching(WebApplication.java:399)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at osgi.enroute.rest.simple.provider.Function.invoke(Function.java:203)
at osgi.enroute.rest.simple.provider.RestMapper.execute(RestMapper.java:333)
at osgi.enroute.rest.simple.provider.RestServlet.service(RestServlet.java:66)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.felix.http.base.internal.handler.ServletHandler.handle(ServletHandler.java:85)
at org.apache.felix.http.base.internal.dispatch.InvocationChain.doFilter(InvocationChain.java:79)
at my.application.CORSFilter.doFilter(CORSFilter.java:75)
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:135)
at org.apache.felix.http.base.internal.dispatch.InvocationChain.doFilter(InvocationChain.java:74)
at org.apache.felix.http.base.internal.dispatch.Dispatcher.dispatch(Dispatcher.java:124)
at org.apache.felix.http.base.internal.DispatcherServlet.service(DispatcherServlet.java:61)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:845)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:583)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:224)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1160)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1092)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:213)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
at org.eclipse.jetty.server.Server.handle(Server.java:518)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:308)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:244)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:246)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:156)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
at java.lang.Thread.run(Unknown Source)

authenticate()当前在调试模式下修改标头以允许在开发应用程序时使用 CORS 并尝试User从标头中传递的令牌中获取一个Authorization...但是,即使我将startAsync()行放在上面,我仍然得到相同的IllegalStateException结果,所以我不认为这是标题修改的问题。

一些谷歌搜索表明,该特定行上的 ISEServletRequestWrapper.java:314表明底层 Felix/Jetty 服务器未设置为允许异步请求。

我还尝试简单地将标头设置为text/event-stream并继续写入响应,但当然它在退出 REST 方法时被关闭。

进一步的调查提供了其他解决方案,包括运行第二个 servlet,该 servlet 被配置为处理异步请求并将其绑定到单独的 URL 模式。当然,这是自己的努力,我不确定多个 servlet 协同工作的效果如何。最好我希望能够从一个 Enroute 应用程序中打开异步响应。

如果可以将航路应用程序配置为允许异步响应,那么我搞砸的设置是什么?

4

1 回答 1

2

叹息......在启动时遇到困难@WebServlet并不断回到白板时找到了答案。搜索“whiteboard async Java”会出现以下HttpWhiteboardConstants设置HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED::

@Component(..., property={...,
     HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED+"=true", ...}...)

@Component但是,这对implementation不起作用REST,而是我只能让它在一个单独的组件中工作,如下所示:

@RequireHttpImplementation
@Component(name="sse", property={
    HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN+"=/sse/*",
    HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED+"=true",
    HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED+"=true"},
    service=Servlet.class)
public final class ServerSideEventServlet extends HttpServlet
{
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response) 
       throws ServletException, IOException
   {
   }
}

Servlet与我的问题平行开始。当我尝试将此配置拉到REST服务器时,我仍然遇到同样的异常。这可能是因为在requestREST 方法之外触摸了 ,这确实是有道理的。

于 2017-10-27T14:39:34.493 回答