tomcat ssi配置及升级导致ssi include错误问题解决

时间:2022-09-30 17:28:25

最近tomcat升级版本时,遇到了ssi解析的问题,记录下解决的过程,还有tomcat ssi配置的要点。

tomcat 配置SSI的两种方式

Tomcat有两种方式支持SSI:Servlet和Filter。

SSIServlet

通过Servlet,org.apache.catalina.ssi.SSIServlet,默认处理”*.shtml”的URL。

配置方式:

修改tomcat的 conf/web.xml文件,去掉下面配置的注释:

<servlet>
<servlet-name>ssi</servlet-name>
<servlet-class>
org.apache.catalina.ssi.SSIServlet
</servlet-class>
<init-param>
<param-name>buffered</param-name>
<param-value>1</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>expires</param-name>
<param-value>666</param-value>
</init-param>
<init-param>
<param-name>isVirtualWebappRelative</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>4</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>ssi</servlet-name>
<url-pattern>*.shtml</url-pattern>
</servlet-mapping>

SSIFilter

通过Filter,org.apache.catalina.ssi.SSIFilter,默认处理”*.shtml”的URL。

配置方式:

修改tomcat的 conf/web.xml文件,打开去掉下面配置的注释:

<filter>
<filter-name>ssi</filter-name>
<filter-class>
org.apache.catalina.ssi.SSIFilter
</filter-class>
<init-param>
<param-name>contentType</param-name>
<param-value>text/x-server-parsed-html(;.*)?</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>expires</param-name>
<param-value>666</param-value>
</init-param>
<init-param>
<param-name>isVirtualWebappRelative</param-name>
<param-value>false</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>ssi</filter-name>
<url-pattern>*.shtml</url-pattern>
</filter-mapping>

注意事项

注意:两种配置方式最好不要同时打开,除非很清楚是怎样配置的。

另外,在Tomcat的conf/context.xml里要配置privileged=”true”,否则有些SSI特性不能生效。

<Context privileged="true">
  • 1
  • 1

历史代码里处理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版本以上,例如:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
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"> </web-app>

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指令代码如下:

<!--#include virtual="/pages/test/intelFilter.shtml"-->

经过对比调试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 <code>ServletContext</code> 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 <code>RequestDispatcher</code> 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);
}
if (child == null)
return (null);
if (context.getCrossContext()) {
// If crossContext is enabled, can always return the context
return child.getServletContext();
} else if (child == context) {
// Can still return the current context
return context.getServletContext();
} else {
// Nothing to return
return (null);
}
}

7.0.58的代码: 
https://svn.apache.org/repos/asf/tomcat/tc7.0.x/tags/TOMCAT_7_0_58/java/org/apache/catalina/core/ApplicationContext.java

那么正确的处理办法是怎样的?

仔细查看Tomcat的SSI配置的说明文档,发现有一个isVirtualWebappRelative的配置,而这个配置默认是false的。

isVirtualWebappRelative - Should "virtual" SSI directive paths be interpreted as relative to the context root, instead of the server root? Default false.

**也就是说,如果要支持“#include virtual=”/b.shtml”绝对路径这种指令,就要配置isVirtualWebappRelative为true。 
但是tomcat默认的SSI配置,以及上面的EnhancedSSIServlet类默认都配置isVirtualWebappRelative为false。**

因此,把EnhancedSSIServlet类里的isVirtualWebappRelative配置为true,重新测试,发现已经可以正常处理”#include virtual=”/b.shtml”指令了。

相关的逻辑处理的代码在org.apache.catalina.ssi.SSIServletExternalResolver.getServletContextAndPathFromVirtualPath( String virtualPath):

protected ServletContextAndPath getServletContextAndPathFromVirtualPath(
String virtualPath) throws IOException {
if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) {
return new ServletContextAndPath(context,
getAbsolutePath(virtualPath));
}
String normalized = RequestUtil.normalize(virtualPath);
if (isVirtualWebappRelative) {
return new ServletContextAndPath(context, normalized);
}
ServletContext normContext = context.getContext(normalized);
if (normContext == null) {
throw new IOException("Couldn't get context for path: "
+ normalized);
}

总结

之前的EnhancedSSIServlet类的配置就不支持”#include virtual=”/b.shtml”,这种绝对路径的SSI指令,而以前版本的Tomcat因为恰好处理了”/test.shtml”这种以”/”开头的url,因此以前版本的Tomcat没有报错。而升级后的Tomcat修正了代码,不再处理这种不合理的绝对路径请求了,所以报“ Couldn’t get context for path”的异常。

把tomcat的ssi配置里的isVirtualWebappRelative设置为true就可以了。

最后,留一个小问题:

tomcat是如何知道处理*.jsp请求的?是哪个servlet在起作用?

tomcat ssi配置及升级导致ssi include错误问题解决的更多相关文章

  1. Apache下开启SSI配置,使html支持include包含

    有的时候,我们的页面有公共的导航栏navbar,公共的脚注footer,那么我们就想把这些公共部分独立成一个html文件,在要引用的地方像引用js,css一样,给包含进来. Apache下开启SSI配 ...

  2. nginx配置 yii2 URL重写规则 SSI配置使shtml

    location / { // 加上红色部分 重写url try_files $uri $uri/ /index.php?$args; if (!-e $request_filename){ rewr ...

  3. Apache下开启SSI配置使html支持include包含

    写页面的同学通常会遇到这样的烦恼,就是页面上的 html 标签越来越多的时候,寻找指定的部分就会很困难,那么能不能像 javascript 一样写在不同的文件中引入呢?答案是有的,apache 能做到 ...

  4. 开启SSI配置使shtml支持include公用的页头页脚

    编写编写项目众多静态文件时,能像php等开发语言一样使用include将页面公有的header/footer/sidebar作为公用.独立.单一的文件引入到各页面上,这样修改这些页面公用部分时就能单独 ...

  5. Windows 的Apache支持SSI配置

    配置SSI什么是shtml? 使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为"服务器端嵌入"或 ...

  6. 在Apache下开启SSI配置

    开启SSI:html.shtml页面include网页文件 使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为&quo ...

  7. 生产环境中tomcat的配置

    生产环境中要以daemon方式运行tomcat 通常在开发环境中,我们使用$CATALINA_HOME/bin/startup.sh来启动tomcat, 使用$CATALINA_HOME/bin/sh ...

  8. SSI简介 与 nginx开启SSI

    Server Side Include : 服务器端嵌入 原理 : 将内容发送到浏览器之前,可以使用“服务器端包含 (SSI)”指令将文本.图形或应用程序信息包含到网页中.因为包含 SSI 指令的文件 ...

  9. tomcat 安全配置文档

    1.配置文档中使用$CATALINA_HOME变量声明为tomcat的安装目录并明确写出了tomcat的配置文件路径,此路径为测试环境的路径,线上系统对应配置文件的路径可能不一样,在进行相关配置时,应 ...

随机推荐

  1. INF文件的安装&sol;卸载命令

    RunDll32 advpack.dll,LaunchINFSection C:\Windows\INF\Office~1.inf,Uninstall,5

  2. YTU 2616&colon; A代码完善--简易二元运算

    2616: A代码完善--简易二元运算 时间限制: 1 Sec  内存限制: 128 MB 提交: 280  解决: 187 题目描述 注:本题只需要提交填写部分的代码,请按照C++方式提交. 编写二 ...

  3. DatagramChannel

    DatagramChannel 最后一个socket通道是DatagramChannel.正如SocketChannel对应Socket,ServerSocketChannel对应ServerSock ...

  4. &lbrack;Oralce&rsqb;Oralce格式化日期

    字符串转日期 1.to_date(日期,'yyyyMMdd') 2.to_date(日期,'yyyyMMdd hh24miss')日期转字符串 TO_CHAR(SYSDATE, 'YYYY-MM-DD ...

  5. htmlparser源码简单分析

    Htmlparser源代码分析 一.根目录下的类 1.Attribute.java 属性类,四个field:mName,mAssignment,mValue,mQuote; 空白标签时:mName=n ...

  6. 用Gitosis搭建Git服务器(经典资料)

    该文档介绍了用Gitosis自己搭建Git服务器,文章来自于<Git权威指南>一书的第31章,讲述详细易懂易操作,是搭建Git服务器绝好资料! 下载地址:http://download.c ...

  7. Javaweb学习笔记——(二十四)——————图书商城项目

    图书商城          环境搭建         1.导入原型             *用户模块             *分类模块             *图书模块              ...

  8. 牛客网noip集训4

    T1 (A)[https://www.nowcoder.com/acm/contest/175/A] 给出 l, r, k,请从小到大输出所有在 [l, r] 范围内,能表示为 k 的非负整数次方的所 ...

  9. MT【45】抛物线外一点作抛物线的切线(尺规作图题)

    注1:S为抛物线焦点 注2:由切线的唯一性,以及切线时可以利用MT[42]评得到三角形全等从而得到切线平分$\angle MQS$得到

  10. cmd变量&comma;参数&comma;for循环&comma;

    @echo offrem  *****************************************************rem  Create By Q_rui CopryRight@_ ...