tomcat ssi配置及升级导致ssi include错误问题解决
最近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时出错了。
/**
* 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);
}
}
那么正确的处理办法是怎样的?
仔细查看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错误问题解决的更多相关文章
- Apache下开启SSI配置,使html支持include包含
有的时候,我们的页面有公共的导航栏navbar,公共的脚注footer,那么我们就想把这些公共部分独立成一个html文件,在要引用的地方像引用js,css一样,给包含进来. Apache下开启SSI配 ...
- nginx配置 yii2 URL重写规则 SSI配置使shtml
location / { // 加上红色部分 重写url try_files $uri $uri/ /index.php?$args; if (!-e $request_filename){ rewr ...
- Apache下开启SSI配置使html支持include包含
写页面的同学通常会遇到这样的烦恼,就是页面上的 html 标签越来越多的时候,寻找指定的部分就会很困难,那么能不能像 javascript 一样写在不同的文件中引入呢?答案是有的,apache 能做到 ...
- 开启SSI配置使shtml支持include公用的页头页脚
编写编写项目众多静态文件时,能像php等开发语言一样使用include将页面公有的header/footer/sidebar作为公用.独立.单一的文件引入到各页面上,这样修改这些页面公用部分时就能单独 ...
- Windows 的Apache支持SSI配置
配置SSI什么是shtml? 使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为"服务器端嵌入"或 ...
- 在Apache下开启SSI配置
开启SSI:html.shtml页面include网页文件 使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为&quo ...
- 生产环境中tomcat的配置
生产环境中要以daemon方式运行tomcat 通常在开发环境中,我们使用$CATALINA_HOME/bin/startup.sh来启动tomcat, 使用$CATALINA_HOME/bin/sh ...
- SSI简介 与 nginx开启SSI
Server Side Include : 服务器端嵌入 原理 : 将内容发送到浏览器之前,可以使用“服务器端包含 (SSI)”指令将文本.图形或应用程序信息包含到网页中.因为包含 SSI 指令的文件 ...
- tomcat 安全配置文档
1.配置文档中使用$CATALINA_HOME变量声明为tomcat的安装目录并明确写出了tomcat的配置文件路径,此路径为测试环境的路径,线上系统对应配置文件的路径可能不一样,在进行相关配置时,应 ...
随机推荐
- vue+vuex+axios+echarts画一个动态更新的中国地图
一. 生成项目及安装插件 # 安装vue-cli npm install vue-cli -g # 初始化项目 vue init webpack china-map # 切到目录下 cd china- ...
- 洛谷P1972 HH的项链
传送门啦 分析: 题目描述不说了,大意是,求一段区间内不同元素的种数. 看到区间,我们大概先想到的是暴力(然后炸掉).线段树.树状数组.分块. 下面给出的是一种树状数组的想法. 首先,对于每一段区间里 ...
- python对象学习
python对象的介绍 python使用对象模型来存储数据,构造任何类型的值都是一个对象,尽管python被当成面向对象的编程语言,但是完全编写不使用任何类和实例的脚本.所有的python对象都拥有三 ...
- Oracle与Sqlserver数据共享
需求:在一个集成平台中有一个主系统使用的是Oralce数据库,子系统使用的SqlServer 数据库,如何让子系统的数据库与主系统的人员同步呢? 思路:通过服务WebService 公开接口 1.与主 ...
- C#基础系列 - 抽象类及其方法的学习
在C#中使用关键字 abstract 来定义抽象类和抽象方法. 不能初始化的类被叫做抽象类,它们只提供部分实现,但是另一个类可以继承它并且能创建它们的实例. "一个包含一个或多个纯虚函数的类 ...
- CI框架整合UEditor编辑器上传功能
最近项目中要使用到富文本编辑器,选用了功能强大的UEditor,接下来就来讲讲UEditor编辑器的上传功能整合. 本文UEditor版本:ueditor1_4_3_utf8_php版本 第一步:部署 ...
- hdu 3537 翻硬币 每次能翻1个 或2个 或3个
N 枚硬币排成一排,有的正面朝上,有的反面朝上.我们从左开始对硬币按1 到N 编号. 第一,游戏者根据某些约束翻硬币,但他所翻动的硬币中,最右边那个硬币的必须是从正面翻到反面. 第二,谁不能翻谁输. ...
- USACO 6.4 Electric Fences
Electric FencesKolstad & Schrijvers Farmer John has decided to construct electric fences. He has ...
- tomcat下程序包的安装与部署
还没亲自在服务器进行部署,但是参考了公司文档,等自己安装部署的时候,再将文档补充完整. 1.初始化数据库 2.修改war包的数据 主要包括的一些配置是数据库的连接配置. 3.将包发布 这个步骤下有几个 ...
- 基于五阶段流水线的RISC-V CPU模拟器实现
RISC-V是源自Berkeley的开源体系结构和指令集标准.这个模拟器实现的是RISC-V Specification 2.2中所规定RV64I指令集,基于标准的五阶段流水线,并且实现了分支预测模块 ...