Jetty:配置上下文
这篇文件讲述配置Jetty上下文的各种选项。
设置上下文路径
上下文路径是一个URL路径的前缀,用于将一个输入请求相应到相应的上下文。Java Servlet Server的URL通常的格式为:http://hostname.com/contextPath/servletPath/pathInfo。假设没有上下文路径,则相应上下文为根上下文,根上下文必须被配置为"/"。
你怎么设置上下文路径依赖你怎么部署web应用(或者ContextHandler):
用内嵌式部署
假设你执行Jetty使用通过编码将Jetty作为内嵌的server的方式(在后面会专门解说怎么实现)。设置上下文路径通过调用ContextHandler实例(或WebAppContext实例)的setContextPath方法实现。
通过命名约定
假设一个web应用被DeploymentManager的WebAppProvider部署,但没实用XML IoC文件。那么WAR文件的名字被用于设置上下文路径。
1)假设WAR文件被命名为myapp.war。那么上下文路径将是/myapp;
2)假设WAR文件被命名为ROOT.WAR(不区分大写和小写),那么上下文路径为/。
3)假设WAR文件被命名为ROOT-foobar.war(不区分大写和小写),按么上下文路径为/,并相应一个“foobar”的虚拟主机(下一节解说)。
不同部署器配置
假设一个web应用被DeploymentManager的WebAppProvider部署,并带有XML IoC文件配置上下文,那么setContextPath方法能够在文件里被调用。比如:
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/test</Set> ... </Configure>
嵌入一个WEB-INF/jetty-web.xml文件
你也能为webapps设置上下文路径通过在WAR包中内嵌一个WEB-INF/jetty-web.xml文件,用相同的XML IoC格式(上面的样例)。
但因为它要求web应用被改动,因此不是一个首先的方式。
配置虚拟主机
一个虚拟主机是为一个IP地址的可选择的名字。注冊在DNS,这样多个域名能够相应到同样的IP。
虚拟主机通过调用setVirtualHosts或addVirtualHost方法设置到上下文。能够通过以下方式之中的一个实现:
1)用webapps目录中的上下文XML文件(看jetty公布版本号中的test.xml文件);
2)用WEB-INF/jetty-web.xml文件(不赞成)。
3)创建一个自己定义的部署器。部署器为同一个webapps目录中的全部上下文绑定配置的虚拟主机;
4)使用内嵌代码调用API设置。
虚拟主机名
Jetty支持以下的虚拟主机名:
1)www.hostname.com
2)*.hostname.com
3)10.0.0.2
4)@ConnectorName:连接器名
5)www.√integral.com
虚拟主机配置举例
虚拟主机能与不论什么ContextHandler的子类的上下文一起使用。让我们看一个使用虚拟主机配置web应用的样例-通过WebAppContext类表示。
假定你有一个server,该server有下面IP地址和域名:
333.444.555.666
127.0.0.1
www.blah.com
www.blah.net
www.blah.org
假定你又一个webapp叫做blah.war,你希望上面的地址和域名都能被路径"/blah"服务,以下就是你须要的在上下文XML文件里的配置:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/blah</Set> <Set name="war"><Property name="jetty.webapps"/>/webapps/blah.war</Set> <Set name="virtualHosts"> <Array type="java.lang.String"> <Item>333.444.555.666</Item> <Item>127.0.0.1</Item> <Item>www.blah.com</Item> <Item>www.blah.net</Item> <Item>www.blah.org</Item> </Array> </Set> </Configure>
为不同的上下文配置不同的虚拟主机集合
你能为不同的上下文配置不同的虚拟主机集合。比如,假定你的足迹有以下的域名:
www.blah.com
www.blah.net
www.blah.org
www.other.com
www.other.net
www.other.org
假定你又两个webapps,一个叫blah.war,你想为域名*.blah.*的请求提供服务。还有一个叫other.war。为*.other.*域名的请求提供服务。
在上下文文件里。blah的配置例如以下:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/blah</Set> <Set name="war"><Property name="jetty.webapps"/>/webapps/blah.war</Set> <Set name="virtualHosts"> <Array type="java.lang.String"> <Item>www.blah.com</Item> <Item>www.blah.net</Item> <Item>www.blah.org</Item> </Array> </Set> </Configure>
这样,以下的url将相应到blah的上下文:
http://www.blah.com/blah
http://www.blah.net/blah
http://www.blah.org/blah
而other的配置为:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/other</Set> <Set name="war"><Property name="jetty.webapps"/>/webapps/other.war</Set> <Set name="virtualHosts"> <Array type="java.lang.String"> <Item>www.other.com</Item> <Item>www.other.net</Item> <Item>www.other.org</Item> </Array> </Set> </Configure>
这样以下的url将会被other上下文处理:
http://www.other.com/other
http://www.other.net/other
http://www.other.org/other
对同一个上下文路径的不同上下文设置不同的虚拟主机集合
考虑和上面同样的场景,我们希望blah.war相应域名*.blah.*。而other.war相应域名*.other.* 。然而。我们希望我们的client都是用上下文路径"/"。
换句话说。我们希望以下的url匹配到blah.war:
http://www.blah.com/
http://www.blah.net/
http://www.blah.org/
类似的,我们希望以下的url相应到other.war:
http://www.other.com/
http://www.other.net/
http://www.other.org/
为了达到这个目地,我们须要全部的webapps都是用相同的上下文路径"/",并能相应到不同的虚拟主机名。
以下是foo的配置:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/</Set> <Set name="war"><Property name="jetty.webapps"/>/webapps/foo.war</Set> <Set name="virtualHosts"> <Array type="java.lang.String"> <Item>www.blah.com</Item> <Item>www.blah.net</Item> <Item>www.blah.org</Item> </Array> </Set> </Configure>
以下是bar的配置:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/</Set> <Set name="war"><Property name="jetty.webapps"/>/webapps/bar.war</Set> <Set name="virtualHosts"> <Array type="java.lang.String"> <Item>www.other.com</Item> <Item>www.other.net</Item> <Item>www.other.org</Item> </Array> </Set> </Configure>
暂时目录
Jetty本身没有暂时目录。可是你能为每一个web应用分配一个目录,用于WAR的解压、JSP的编译等。假设你没有分配一个暂时目录。当你的web应用启动时,Jetty将依照须要创建一个。
不管你是指定一个。或者让Jetty创建一个,你都能够选择在web应用停止的时候是否删除它。
默认暂时目录
默认。Jetty将为每一个web应用创建一个暂时目录,目录的名字能够是以下的形式:
"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+".dir"
比如:
jetty-0.0.0.0-8080-test.war-_test-any-8900275691885214790.dir
上面表示:0.0.0.0是主机地址,8080是port,test.war是resourceBase。test是上下文路径(/转化为_)。any是虚拟主机。randomdigits是唯一数字串。
一旦这个暂时目录被创建。能够通过上下文属性值javax.servlet.context.tempdir获取到。
暂时目录的位置
默认。jetty将在java.io.tmpdir系统属性指定的目录内创建暂时目录,你能设置上下文属性org.eclipse.jetty.webapp.basetempdir来指定暂时目录的父目录,注意这个父目录必须存在且是可写的。
你能在上下文文件里设置该属性。或者通过编码。以下是上下文文件里设置的样例:
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/test</Set> <Set name="war">foo.war</Set> <Call name="setAttribute"> <Arg>org.eclipse.jetty.webapp.basetempdir</Arg> <Arg>/home/my/foo</Arg> </Call> </Configure>
等效的代码中设置的样例:
WebAppContext context = new WebAppContext(); context.setContextPath("/test"); context.setWar("foo.war"); context.setAttribute("org.eclipse.jetty.webapp.basetempdir", "/tmp/foo");
指定暂时目录
你能有两种方式指定暂时目录:
WebAppContext.setTempDirectory(String dir)
以下是使用上下文文件配置:
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/test</Set> <Set name="war">foo.war</Set> <Set name="tempDirectory">/some/dir/foo</Set> </Configure>
以下是使用编码实现:
WebAppContext context = new WebAppContext(); context.setContextPath("/test"); context.setWar("foo.war"); context.setTempDirectory(new File("/some/dir/foo"));
设置javax.servlet.context.tempdir context属性
在上下文文件里配置:
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/test</Set> <Set name="war">foo.war</Set> <Call name="setAttribute"> <Arg>javax.servlet.context.tempdir</Arg> <Arg>/some/dir/foo</Arg> </Call> </Configure>
使用编码实现:
WebAppContext context = new WebAppContext(); context.setContextPath("/test"); context.setWar("foo.war"); context.setAttribute("javax.servlet.context.tempdir", "/some/dir/foo");
一旦暂时目录被创建,它的一个File实例将被保存在web应用的javax.servlet.context.tempdir属性中。
持久化暂时目录
默认情况下Jetty将不保留暂时目录,假设你想保留暂时目录。须要调用WebAppContext.setPersistTempDirectory(true)。
须要注意的是,假设你没有指定暂时目录。Jetty将每次都创建一个新的暂时目录,这样你的暂时目录将不断堆积。
为WebApp指定port/连接器
有时你希望从不同的port/连接器为不同的web应用提供服务,最简单的方式就是创建多个Server实例,然而,假设上下文须要共享资源(比如数据库、认证),或者假设web应用的port映射没被清晰的划分。那么能够考虑使用命名的连接器机制。
创建多个Server实例
假设你使用编码方式。仅仅须要创建多个Server对象,然后按须要配置就能够了。假设你使用XML文件配置。须要设置jetty.xml的Configure元素的id域。以下是一个样例:
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure id="OtherServer" class="org.eclipse.jetty.server.Server"> <Set name="handler"> <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection"> <Set name="handlers"> <Array type="org.eclipse.jetty.server.Handler"> <Item> <New id="OtherContexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/> </Item> <Item> <New class="org.eclipse.jetty.server.handler.DefaultHandler"/> </Item> </Array> </Set> </New> </Set> <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.ServerConnector"> <Arg name="server"><Ref refid="OtherServer" /></Arg> <Set name="port">8888</Set> </New> </Arg> </Call> <Call name="addBean"> <Arg> <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> <Set name="contexts"> <Ref refid="OtherContexts" /> </Set> <Call id="webappprovider" name="addAppProvider"> <Arg> <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> <Set name="monitoredDirName"><Property name="jetty.home" default="." />/other-webapps</Set> <Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set> <Set name="configurationManager"> <New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager"/> </Set> </New> </Arg> </Call> </New> </Arg> </Call> </Configure>
1)改变id="Server"到一个新的server名:<Configure id="OtherServer" class="org.eclipse.jetty.server.Server"> ;
2)改变连接器的server參数的refid到新的server:<Arg name="server"><Ref refid="OtherServer" /></Arg>;
3)确保全部对jetty.port属性的引用都被重命名或者使用新值;
4)确保全部部署器的AppProvider引用的”webapps“相应到不同的应用。
为了执行otherServer。添加配置文件到命令行:
java -jar start.jar jetty-otherserver.xml
命名的连接器
能够使用一个对虚拟主机机制的扩展。即命名的连接器,来确保一些web应用仅被特定的连接器处理。
假设一个连接器有一个名字”MyConnector“,用setName方法设置,那么这能相应到特定的虚拟主机名”@MyConnector“。
创建自己定义error页
以下将介绍几个方法在Jetty中自己定义error页。
在web.xml中定义error页
你能用标准webapp配置文件webapp/WEB-INF/web.xml的error-page元素映射errors到指定的URLs。这个原书创建了一个在error-code或exception-type到资源location的映射关系。
error-code:整数值(integer)
exception-type:一个Java异常的类名
location:相对于web应用的root的资源位置,以"/"開始
error code的样例:
<error-page> <error-code>404</error-code> <location>/jspsnoop/ERROR/404</location> </error-page>
异常的样例:
<error-page> <exception-type>java.io.IOException</exception-type> <location>/jspsnoop/IOException</location> </error-page>
这个映射将导致请求重定向到一个通常的URL,将被作为一个通常的请求进行处理。因此请求的对象可能为静态资源、一个JSP或一个filter和/或servlet。
当处理一个由错误重定向产生的请求时。以下的请求属性被设置。并在生成动态页时可用:
1)javax.servlet.error.exception
导致error(或null)的异常实例
2)javax.servlet.error.exception_type
导致error(或null)的异常实例的类名
3)javax.servlet.error.message
错误信息
4)javax.servlet.error.request_uri
出错请求的URI
5)javax.servlet.error.servlet_name
出错请求被分发到的servlet的Servlet名
6)javax.servlet.error.status_code
错误的状态码(比如:404,500等)
配置error页上下文文件
你能用上下文IoC XML 文件配置默认error页,这样做的优点是比web.xml中配置更加灵活,特别在须要error code范围支持时。上下文文嘉通常在${jetty.home}/webapps/,以下是一个样例:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.eclipse.org/configure.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/test</Set> <Set name="war"> <SystemProperty name="jetty.home" default="."/>/webapps/test </Set> <!-- by Code --> <Get name="errorHandler"> <Call name="addErrorPage"> <Arg type="int">404</Arg> <Arg type="String">/jspsnoop/ERROR/404</Arg> </Call> </Get> <!-- by Exception --> <Get name="errorHandler"> <Call name="addErrorPage"> <Arg> <Call class="java.lang.Class" name="forName"> <Arg type="String">java.io.IOException</Arg> </Call> </Arg> <Arg type="String">/jspsnoop/IOException</Arg> </Call> </Get> <!-- by Code Range --> <Get name="errorHandler"> <Call name="addErrorPage"> <Arg type="int">500</Arg> <Arg type="int">599</Arg> <Arg type="String">/dump/errorCodeRangeMapping</Arg> </Call> </Get> </Configure>
自己定义ErrorHandler类
假设没有error页映射被定义,或者假设error页资源自身发生了错误。那么error页将通过ErrorHandler的一个实例产生,ErrorHandler通过Context或者Server配置。
ErrorHandler能实现以下的部分或全部方法:
void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message) throws IOException void writeErrorPage(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks) throws IOException void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message) throws IOException void writeErrorPageBody(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks) throws IOException void writeErrorPageMessage(HttpServletRequest request, Writer writer, int code, String message, String uri) throws IOException void writeErrorPageStacks(HttpServletRequest request, Writer writer) throws IOException
一个ErrorHandler实例可以调用ContextHandler.setErrorHandler设置,能通过编码或者上下文IoC XML实现,比如:
<Configure class="org.eclipse.jetty.server.handler.ContextHandler"> ... <Set name="errorHandler"> <New class="com.acme.handler.MyErrorHandler"/> </Set> ... </Configure> ErrorHandler实例也能够作为一个bean加入到Server实例中,能通过编码调用Server.addBean(Object)实现,或者在jetty.xml中配置: <Configure id="Server" class="org.eclipse.jetty.server.Server"> ... <Call name="addBean"> <Arg> <New class="com.acme.handler.MyErrorHandler"/> </Arg> </Call> ... </Configure>
设置最大窗口大小
Jetty限制来自浏览器或者其他client发送到服务端的数据大小。这有利于防止恶意用户的攻击。通过送大量的数据到服务端。Jetty同意的默认最大值是200000bytes。你能改变这个默认值,为特定的webapp、或者在一个特定Server实例的全部webapp、或者在同样JVM下的全部webapp。
为单个webapp
调用方法为:ContextHandler.setMaxFormContentSize(int maxSize);
你能够在webapp的上下文XML部署描写叙述符文件里设置,或者在jetty-web.xml文件(在webapp的WEB-INF文件夹下)中设置,设置的语法同样:
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- Max Form Size --> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <Set name="maxFormContentSize">200000</Set> </Configure>
为同样Server的全部WebApp
以下是详细的样例:
<Configure class="org.eclipse.jetty.server.Server"> <Call name="setAttribute"> <Arg>org.eclipse.jetty.server.Request.maxFormContentSize</Arg> <Arg>200000</Arg> </Call> </Configure>
为同样JVM下的全部WebApp
用系统属性org.eclipse.jetty.server.Request.maxFormContentSize。能通过命令行指定。或者在start.ini文件里设置。