我有一个Tomcat 8 Web应用程序,它使用2 MB的png图像作为"启动/登陆页面"背景。图像在外部样式表中引用。
如果我清除浏览器缓存,直接请求图像的URL,但在加载之前离开图像,它将完全杀死我的Web应用程序。它无法再为任何请求提供任何响应。
我收到此错误:
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:396)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:344)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:421)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:409)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:97)
at org.apache.catalina.servlets.DefaultServlet.copy(DefaultServlet.java:1795)
at org.apache.catalina.servlets.DefaultServlet.serveResource(DefaultServlet.java:919)
at org.apache.catalina.servlets.DefaultServlet.doGet(DefaultServlet.java:400)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at other.JsCssImgResponseHeaderFilter.doFilter(JsCssImgResponseHeaderFilter.java:36)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at other.CatchAnyExceptionFilter.doFilter(CatchAnyExceptionFilter.java:39)
我试图捕获该异常(或任何异常)并显示友好的ErrorPage.jsp,但我无法重定向到ErrorPage,因为响应已经提交。
我无法在测试环境中复制它,但我可以在生产中随意中断。
有谁知道我的选择是什么来解决这类问题?提前谢谢。
BTW,这是我的Filter类的doFilter方法:
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain fc) throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession();
try
{
fc.doFilter(req, res);
// Have learned that response headers should not be set until we have determined there won't be an exception.
// Can't easily redirect or forward (to an error page, for example) if headers have already been committed.
if (SessionHelper.hasNeedsJsCssImgResponseHeaderFlag(request))
{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, JsCssImgResponseHeaderFilter.SECONDS_TO_CACHE);
response.setHeader("Cache-Control", "PUBLIC, max-age=" + JsCssImgResponseHeaderFilter.SECONDS_TO_CACHE + ", must-revalidate");
response.setHeader("Expires", DateUtils.getDateInExpiresHeaderFormat(cal.getTime()));
}
else if (SessionHelper.hasNeedsDynamicPageResponseHeaderFlag(request))
{
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Expires", "Mon, 25 Nov 2013 00:00:01 GMT"); // in the past
}
else if (SessionHelper.hasNeedsRestServicesResponseHeaderFlag(request))
{
// CORS - Cross Origin Resource Sharing: allow service requests from other domains --
// such as local development domains hosting AngularJS projects.
response.setHeader("Access-Control-Allow-Origin", "http://localhost.domain.com:8080");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
// response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With");
}
}
catch (Exception e)
{
SessionHelper.setErrorPageException(req, session, e);
final String uri = request.getRequestURI();
final String playerName = SessionHelper.getLoggedInPlayerName(session);
String outerLogEntryText = "Player = " + playerName + " - IP = " + request.getRemoteAddr() +
" - Mobile = " + SessionHelper.isMobileBrowser(request) +
" - URI = " + uri + " - Exception MSG = " + e.getMessage();
LogUtils.writeLogEntry(outerLogEntryText, true, e);
SessionHelper.setRedirectPage(session, SessionHelper.ERROR_PAGE_PATH);
}
finally
{
String redirectPage = SessionHelper.getRedirectPage(session);
SessionHelper.clearRedirectPage(session);
if (redirectPage != null)
{
if (response.isCommitted())
{
// Article: http://stackoverflow.com/questions/11305563/cause-of-servlets-response-already-committed
System.out.println("Response has been committed. Cannot redirect to: " + redirectPage);
}
else
{
response.sendRedirect(redirectPage);
}
}
}
}
问题发生时,我的响应已经提交......"输出语句确实已写入,因此它不会重定向到我的错误页面。这就是我的挑战:当发生这种情况时如何重定向某个地方 - 或采取更好/无害的行动。
答案 0 :(得分:1)
进行一些更改后,问题在生产中没有发生。最有影响力的变化是减小背景/启动图像的大小。另一个变化是我将Tomcat Connector connectionTimeout属性设置增加了6倍。