(点击
上方公众号
,可快速关注)
来源:hengyunabc ,
hengyunabc.github.io/tomcat-ssi-problem/
如有好文章投稿,请点击 → 这里了解详情
最近tomcat升级版本时,遇到了ssi解析的问题,记录下解决的过程,还有tomcat ssi配置的要点。
tomcat 配置SSI的两种方式
Tomcat有两种方式支持SSI:Servlet和Filter。
SSIServlet
通过Servlet,org.apache.catalina.ssi.SSIServlet,默认处理”*.shtml”的URL。
配置方式
:
修改tomcat的 conf/web.xml文件,去掉下面配置的注释:
ssi
org.apache.catalina.ssi.SSIServlet
buffered
1
debug
0
expires
666
isVirtualWebappRelative
false
4
ssi
*.shtml
SSIFilter
通过Filter,org.apache.catalina.ssi.SSIFilter,默认处理”*.shtml”的URL。
配置方式:
修改tomcat的 conf/web.xml文件,打开去掉下面配置的注释:
ssi
org.apache.catalina.ssi.SSIFilter
contentType
text/x-server-parsed-html(;.*)?
debug
0
expires
666
isVirtualWebappRelative
false
ssi
*.shtml
注意事项
注意:两种配置方式最好不要同时打开,除非很清楚是怎样配置的。
另外,在Tomcat的conf/context.xml里要配置privileged=”true”,否则有些SSI特性不能生效。
历史代码里处理SSI的办法
在公司的历史代码里,在一个公共的jar包里通过自定义一个EnhancedSSIServlet,继承了Tomcat的org.apache.catalina.ssi.SSIServlet来实现SSI功能的。
@WebServlet(name="ssi",
initParams={@WebInitParam(name="buffered", value="1"), @WebInitParam(name="debug", value="0"),
@WebInitParam(name="expires", value="666"), @WebInitParam(name="isVirtualWebappRelative", value="0"),
@WebInitParam(name="inputEncoding", value="UTF-8"), @WebInitParam(name="outputEncoding", value="UTF-8") },
loadOnStartup=1, urlPatterns={"*.shtml"}, asyncSupported=true)
public class EnhancedSSIServlet extends SSIServlet {
其中@WebServlet是Servlet3.0规范里的,所以使用到web-common的web项目的web.xml文件都要配置为3.0版本以上,例如:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
Tomcat是启动Web应用时,会扫描所有@WebServlet的类,并初始化。
所以在使用到历史代码的项目都只能使用Tomcat服务器,并且不能在tomcat的conf/web.xml里打开SSI相关的配置。
Tomcat版本升级的问题
Tomcat版本从7.0.57升级到7.0.59过程中,出现了无法解析SSI include指令的错误:
SEVERE: #include--Couldn't include file: /pages/test/intelFilter.shtml
java.io.IOException: Couldn't get context for path: /pages/test/intelFilter.shtml
at org.apache.catalina.ssi.SSIServletExternalResolver.getServletContextAndPathFromVirtualPath(SSIServletExternalResolver.java:422)
at org.apache.catalina.ssi.SSIServletExternalResolver.getServletContextAndPath(SSIServletExternalResolver.java:465)
at org.apache.catalina.ssi.SSIServletExternalResolver.getFileText(SSIServletExternalResolver.java:522)
at org.apache.catalina.ssi.SSIMediator.getFileText(SSIMediator.java:161)
at org.apache.catalina.ssi.SSIInclude.process(SSIInclude.java:50)
at org.apache.catalina.ssi.SSIProcessor.process(SSIProcessor.java:159)
at com.test.webcommon.servlet.EnhancedSSIServlet.processSSI(EnhancedSSIServlet.java:72)
at org.apache.catalina.ssi.SSIServlet.requestHandler(SSIServlet.java:181)
at org.apache.catalina.ssi.SSIServlet.doPost(SSIServlet.java:137)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:604)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:543)
at org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:954)
at org.apache.jsp.pages.lottery.jczq.index_jsp._jspService(index_jsp.java:107)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:395)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:339)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
仔细查看源代码后,发现不能处理的include指令代码如下:
经过对比调试Tomcat的代码,发现是在7.0.58版本时,改变了处理URL的方法,关键的处理函数是
org.apache.catalina.core.ApplicationContext.getContext( String uri)
在7.0.57版本前,Tomcat在处理处理像/pages/test/intelFilter.shtml这样的路径时,恰好循环处理了”/“字符,使得childContext等于StandardContext,最终由StandardContext处理了/pages/test/intelFilter.shtml的请求。
这个代码实际上是错误的,不过恰好处理了include virtual的情况。
在7.0.58版本修改了处理uri的代码,所以在升级Tomcat到7.0.59时出错了。
7.0.57版的代码:
https://svn.apache.org/repos/asf/tomcat/tc7.0.x/tags/TOMCAT_7_0_57/java/org/apache/catalina/core/ApplicationContext.java
/**
* Return a
ServletContext
object that corresponds to a
* specified URI on the server. This method allows servlets to gain
* access to the context for various parts of the server, and as needed
* obtain
RequestDispatcher
objects or resources from the
* context. The given path must be absolute (beginning with a "/"),
* and is interpreted based on our virtual host's document root.
*
* @param uri Absolute URI of a resource on the server
*/
@Override
public ServletContext getContext(String uri) {
// Validate the format of the specified argument
if ((uri == null) || (!uri.startsWith("/")))
return (null);
Context child = null;
try {
Host host = (Host) context.getParent();
String mapuri = uri;
while (true) {
child = (Context) host.findChild(mapuri);
if (child != null)
break;
int slash = mapuri.lastIndexOf('/');
if (slash < 0)
break;
mapuri = mapuri.substring(0, slash);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
return (null);