Jetty、Spring 和 SPDY 的 Web 服务器日志中的异常

Posted

技术标签:

【中文标题】Jetty、Spring 和 SPDY 的 Web 服务器日志中的异常【英文标题】:Exception in web server logs with Jetty, Spring, and SPDY 【发布时间】:2014-08-24 01:06:13 【问题描述】:

在对 Spring MVC Web 应用程序进行休息调用时,我收到以下错误消息。浏览器收到正确的响应,但我希望异常消失。任何帮助都会很棒。

我正在使用 Jetty 9.2.0.v20140526、Spring 框架 4.0.5.RELEASE 和 NPN 1.1.6.v20130911 (SPDY) 运行 Web 服务器

错误信息

[STDERR] java.lang.IllegalStateException: not lastContent, no content and no responseInfo!
[STDERR]    at org.eclipse.jetty.spdy.server.http.HttpTransportOverSPDY.send(HttpTransportOverSPDY.java:164)
[STDERR]    at org.eclipse.jetty.spdy.server.http.HttpTransportOverSPDY.send(HttpTransportOverSPDY.java:97)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.sendResponse(HttpChannel.java:733)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.write(HttpChannel.java:766)
[STDERR]    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:134)
[STDERR]    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:127)
[STDERR]    at org.eclipse.jetty.server.HttpOutput.flush(HttpOutput.java:229)
[STDERR]    at java.io.FilterOutputStream.flush(FilterOutputStream.java:140)
[STDERR]    at org.eclipse.jetty.servlets.gzip.AbstractCompressedStream.flush(AbstractCompressedStream.java:125)
[STDERR]    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:209)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:143)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:89)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:193)
[STDERR]    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:122)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
[STDERR]    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
[STDERR]    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
[STDERR]    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
[STDERR]    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
[STDERR]    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
[STDERR]    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
[STDERR]    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
[STDERR]    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
[STDERR]    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
[STDERR]    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:751)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1666)
[STDERR]    at org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83)
[STDERR]    at org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:351)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1645)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:564)
[STDERR]    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
[STDERR]    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
[STDERR]    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221)
[STDERR]    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1111)
[STDERR]    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:498)
[STDERR]    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:183)
[STDERR]    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1045)
[STDERR]    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
[STDERR]    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:199)
[STDERR]    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
[STDERR]    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:98)
[STDERR]    at org.eclipse.jetty.server.Server.handle(Server.java:461)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:284)
[STDERR]    at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:241)
[STDERR]    at org.eclipse.jetty.spdy.server.http.HttpChannelOverSPDY.run(HttpChannelOverSPDY.java:87)
[STDERR]    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:607)
[STDERR]    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:536)
[STDERR]    at java.lang.Thread.run(Thread.java:744)

Spring 代码来自我的控制器

@Controller
public class TestController 
    @RequestMapping(value="/run/test", method=RequestMethod.GET, produces="text/plain")
    @ResponseBody
    protected String runTest() throws IOException 
        return "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012";
    

如果我使返回值的大小更小,它最终将毫无例外地工作。不知道为什么大尺寸是个问题...

Maven Plugin Config 从 pom.xml 启动 Jetty

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.2.0.v20140526</version>
    <configuration>
        <scanIntervalSeconds>5</scanIntervalSeconds>
        <stopKey>STOP</stopKey>
        <stopPort>9999</stopPort>
        <jettyXml>src/main/etc/jetty.xml, src/main/etc/jetty-spdy.xml</jettyXml>
        <contextXml>src/main/etc/context.xml</contextXml>
        <waitForChild>true</waitForChild>
        <jvmArgs>-Xbootclasspath/p:$settings.localRepository/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Dspring.profiles.active=dev</jvmArgs>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty.spdy</groupId>
            <artifactId>spdy-http-server</artifactId>
            <version>9.2.0.v20140526</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlets</artifactId>
            <version>9.2.0.v20140526</version>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-rewrite</artifactId>
          <version>9.2.0.v20140526</version>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-jsp</artifactId>
          <version>9.2.0.v20140526</version>
        </dependency>
    </dependencies>
</plugin>

更新:如果我删除 gzip 的 servlet 过滤器,它就可以工作。

来自 web.xml

<filter>
    <filter-name>GzipFilter</filter-name>
    <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
    <init-param>
        <param-name>mimeTypes</param-name>
        <param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml,application/json</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

【问题讨论】:

我试过你的休息端点把它丢给我,在tomcat上运行。无异常返回字符串,等待其他响应。 如果我关闭 NPN (SPDY) 支持,那么一切正常。出于性能原因,我希望启用 NPN。 【参考方案1】:

当我尝试在空流上flush() 时,我遇到了类似的异常。它只发生在 SPDY 上,所以对于这个协议,我有 flush() 的特殊版本,它检查是否可以刷新流。

在我的输出流中flush() 看起来像:

synchronized public void flush()
        throws IOException
    
    // out.flush() do not work on an empty SPDY output stream!!!
    // it ends with:
    // java.lang.IllegalStateException: not lastContent, no content and no responseInfo!
    //    at org.eclipse.jetty.spdy.server.http.HttpTransportOverSPDY.send(HttpTransportOverSPDY.java:164)
    // this is a reason for "flushed" variable
    if (flushed)
        return;
    out.flush();
    flushed = true;
     // flush

write() 方法中,如果我将一些字节写入输出流,我会设置flushed = false

我的班级使用out = response.getOutputStream(),它可以是 SPDY 输出流(会引发异常),也可以是 HTTP/HTTPS 输出流,它可以是 flush() 空流而不会出现错误。

【讨论】:

如您所见,我使用自己的输出。我不知道如何使用我在您的问题中看到的 XML 配置来做到这一点。【参考方案2】:

您运行的是什么版本的 Java?尝试改变它并比较结果。另外,尝试使用过滤器的bufferSizeminGzipSize 初始化参数。请参阅文档here

【讨论】:

我正在使用java-7

以上是关于Jetty、Spring 和 SPDY 的 Web 服务器日志中的异常的主要内容,如果未能解决你的问题,请参考以下文章

Jetty:可以使用 SPDY/3.1 吗?

使用开箱即用的 SPDY 运行 Jetty

Jetty 9.0 SPDY 嵌入式配置

如何使用 ALPN 使用 SPDY 运行 Jetty?

SPDY “Hello server” 与 Jetty

如何在 JDK8 上使用 SPDY 运行 Jetty?