Настройка приложения OSGI Enroute REST для разрешения асинхронных запросов
В настоящее время я пытаюсь настроить приложение 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
так что я не думаю, что это проблема модификации заголовка.
Некоторое прибегая к помощи поднял, что ISE на этой конкретной линии ServletRequestWrapper.java:314
указывает, что базовый сервер Felix/Jetty не настроен на разрешение асинхронных запросов.
Я также попытался просто установить заголовок text/event-stream
и продолжать писать в ответ, но, конечно, он был закрыт при выходе из метода REST.
Дальнейшее исследование предоставило другие решения, в том числе запуск второго сервлета, который настроен для обработки асинхронных запросов и привязки его к отдельному шаблону URL. Это, конечно, собственное усилие, и я не уверен, насколько хорошо несколько сервлетов будут играть вместе. Желательно, чтобы я мог просто открывать асинхронные ответы из одного приложения Enroute.
Если есть возможность настроить приложение enroute для разрешения асинхронных ответов, какой параметр я пропускаю?
1 ответ
Вздох... нашел ответ, испытывая трудности с получением @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
сервер, я все еще получил то же исключение. Это может быть потому, что request
затрагивается вне метода REST, что имеет смысл.