问题描述
将应用程序迁移到 Struts 2 和 Tiles 3.0.0 后,其中一个页面抛出以下异常
严重:servlet jsp 的 Servlet.service() 抛出异常 java.io.IOException:流关闭于 org.apache.jasper.runtime.JspWriterImpl.ensureOpen(JspWriterImpl.java:210) 在 org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:115) 在 org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:194) 在 org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:126) 在 org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:80) 在 org.apache.jsp.pages.common.baseLayout_jsp._jspService(baseLayout_jsp.java:178) 在 org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:727) 在 org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432) 在 org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390) 在 org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:727) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:
当我查看 baseLayout_jsp.java 的源代码时,我看到以下行抛出该异常
finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
但是baseLayout.jsp只有html和tiles代码
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-tags.tld" prefix="s"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<s:property value="getText('label.version')"/>
<html>
<HEAD>
<Meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" />
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<Meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<Meta name="GENERATOR" content="IBM Software Development Platform">
<TITLE><tiles:getAsstring name="title" ignore="true"/></TITLE>
<link href="<s:url value='/css/styles.css'/>" type=text/css rel=styleSheet>
<link href="<s:url value='/css/sor_styles.css'/>" type=text/css rel=styleSheet>
<link href="<s:url value='/css/ucd_styles.css'/>" type=text/css rel=styleSheet>
<script language="JavaScript" src="<s:url value='/js/common/app.js'/>"></script>
<script language="JavaScript" src="<s:url value='/js/common/validations.js'/>"></script>
</HEAD>
<BODY>
<TABLE border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
<TBODY>
<TR>
<TD height="66" colspan="2"><tiles:insertAttribute name="header" /><s:debug value="PAGE TESTING"/></TD>
</TR>
<TR>
<TD width="100%" height="100%" valign="top">
<div id="mainBody">
<tiles:insertAttribute name="tabs" />
<tiles:insertAttribute name="here" />
<tiles:insertAttribute name="error_response" />
<tiles:insertAttribute name="body" />
</div>
</TD>
</TR>
<TR>
<TD colspan="2"><tiles:insertAttribute name="footer" /></TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</html>
知道为什么我会看到这个异常吗?我在那里进行了搜索,但示例显示大多数页面在遇到此异常时都使用了 Stream 编写器,但在我的情况下则不然。
解决方法
总结:
所提供示例中的 page
指令距离 JSP 文件的开头很远,这可能会触发响应的提交,从而导致尝试设置 Content-Type
标头时失败的响应。
将带有 page
和 contentType
属性的 pageEncoding
指令放在 JSP 文件的第一行。
<%@ page contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/struts-tags.tld" prefix="s"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<s:property value="getText('label.version')"/>
<!-- rest of the page -->
...
参考:
Apache Tomcat 7 根据 JSP Specification 2.2 支持 The mapping between the specifications and the respective Apache Tomcat versions。
根据 JSP Specification 2.2 节 JSP.1.10.1 页面指令(重点是我的):
一个翻译单元(JSP 源文件和通过 include
指令包含的任何文件)可以包含多个 page
指令的实例,所有属性都将应用于整个翻译单元(即页面指令与位置无关)。 这种位置独立性的一个例外是在确定页面字符编码时使用 pageEncoding
和 contentType
属性;为此,它们应该出现在页面的开头(参见 JSP.4.1 部分)。
Jakarta Server Pages 3.0 规范中也有相同的声明。