配置 OSGI Enroute REST 应用程序以允许异步请求
Configuring OSGI Enroute REST application to allow async requests
我目前正在尝试配置 REST 应用程序以启用 Server-side 事件发送到使用 EventSource
的客户端。当前,我在尝试打开与 REST 请求的异步连接时 运行 陷入 IllegalStateException
,这似乎是服务器未配置为允许异步请求的结果。
一些代码
@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.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.run(QueuedThreadPool.java:572)
at java.lang.Thread.run(Unknown Source)
其中 authenticate()
当前在 调试 模式下修改 headers 以在开发应用程序时允许 CORS 并尝试获得 User
从在 Authorization
header...这是header修改的问题。
一些谷歌搜索表明特定行 ServletRequestWrapper.java:314
上的 ISE 表明底层 Felix/Jetty 服务器未设置为允许异步请求。
我也尝试简单地将 header 设置为 text/event-stream
并继续写入响应,但当然它在退出 REST 方法时关闭。
进一步的调查提供了其他解决方案,包括 运行 第二个 servlet,它被配置为处理异步请求并将其绑定到单独的 URL 模式。也就是说,当然,这是自己的努力,我不确定多个 servlet 一起玩的效果如何。最好我希望能够从一个 Enroute 应用程序打开异步响应。
如果可以将航路应用程序配置为允许异步响应,那么我搞砸的设置是什么?
叹息...在难以启动 @WebServlet
并不断返回白板时找到了答案。搜索 'whiteboard async Java' 会出现 HttpWhiteboardConstants
设置:HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED
:
@Component(..., property={...,
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED+"=true", ...}...)
然而,这在 @Component
实现 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
服务器时,我仍然遇到同样的异常。可能是因为在 REST 方法之外触及 request
,这确实有意义。
我目前正在尝试配置 REST 应用程序以启用 Server-side 事件发送到使用 EventSource
的客户端。当前,我在尝试打开与 REST 请求的异步连接时 运行 陷入 IllegalStateException
,这似乎是服务器未配置为允许异步请求的结果。
一些代码
@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.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.run(QueuedThreadPool.java:572)
at java.lang.Thread.run(Unknown Source)
其中 authenticate()
当前在 调试 模式下修改 headers 以在开发应用程序时允许 CORS 并尝试获得 User
从在 Authorization
header...这是header修改的问题。
一些谷歌搜索表明特定行 ServletRequestWrapper.java:314
上的 ISE 表明底层 Felix/Jetty 服务器未设置为允许异步请求。
我也尝试简单地将 header 设置为 text/event-stream
并继续写入响应,但当然它在退出 REST 方法时关闭。
进一步的调查提供了其他解决方案,包括 运行 第二个 servlet,它被配置为处理异步请求并将其绑定到单独的 URL 模式。也就是说,当然,这是自己的努力,我不确定多个 servlet 一起玩的效果如何。最好我希望能够从一个 Enroute 应用程序打开异步响应。
如果可以将航路应用程序配置为允许异步响应,那么我搞砸的设置是什么?
叹息...在难以启动 @WebServlet
并不断返回白板时找到了答案。搜索 'whiteboard async Java' 会出现 HttpWhiteboardConstants
设置:HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED
:
@Component(..., property={...,
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED+"=true", ...}...)
然而,这在 @Component
实现 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
服务器时,我仍然遇到同样的异常。可能是因为在 REST 方法之外触及 request
,这确实有意义。