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类表示。假定你有一个服务器,该服务器有以下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.* 。然而,我们希望我们的客户端都是用上下文路径"/"。
换句话说,我们希望下面的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是端口,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指定端口/连接器

有时你希望从不同的端口/连接器为不同的web应用提供服务,最简单的方式就是创建多个Server实例,然而,如果上下文需要共享资源(例如数据库、认证),或者如果web应用的端口映射没被清晰的划分,那么可以考虑使用命名的连接器机制。

创建多个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限制来自浏览器或者其它客户端发送到服务端的数据大小,这有利于防止恶意用户的攻击,通过送大量的数据到服务端。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文件中设置。

你可能感兴趣的:(框架,jetty,Web应用)