RewriteHandler基于一套规则匹配一个请求,然后根据匹配的规则修改请求。最常见的是重写请求的URI,但是不仅限于此:规则能被配置为重定向响应、设置一个cookie或者响应的响应代码、修改header,等等。
标准Jetty发布中包含jetty-rewrite模块JAR,在lib/jetty-rewrite-*.jar,和一个例子配置文件,在etc/jetty-rewrite.xml。为了激活重写模块,用例子配置文件,用如下命令启动Jetty:
$ java -jar start.jar OPTIONS=default,rewrite etc/jetty.xml etc/jetty-rewrite.xml
注意:如果你正在使用例子test webapp运行标准Jetty发布,有一个重写模块的demo在http://localhost:8080/rewrite/ 。
rules通过使用jetty.xml配置。下面的例子文件展示怎么为server增加重写handler:
<Configure id="Server" class="org.eclipse.jetty.server.Server"> <!-- create and configure the rewrite handler --> <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler"> <Set name="rewriteRequestURI">true</Set> <Set name="rewritePathInfo">false</Set> <Set name="originalPathAttribute">requestedPath</Set> <!-- redirect the response. This is a redirect which is visible to the browser. After the redirect, the browser address bar will show /redirected --> <Call name="addRule"> <Arg> <New class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule"> <Set name="pattern">/redirect/*</Set> <Set name="replacement">/redirected</Set> </New> </Arg> </Call> <!-- rewrite the request URI. This is an internal rewrite, visible to server, but the browser will still show /some/old/context --> <Call name="addRule"> <Arg> <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule"> <Set name="pattern">/some/old/context</Set> <Set name="replacement">/some/new/context</Set> </New> </Arg> </Call> <!-- reverse the order of the path sections. Internal rewrite --> <Call name="addRule"> <Arg> <New class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule"> <Set name="regex">/reverse/([^/]*)/(.*)</Set> <Set name="replacement">/reverse/$2/$1</Set> </New> </Arg> </Call> </New> <!-- add the rewrite handler to the server --> <Set name="handler"><Ref id="Rewrite" /></Set> </Configure>
更多的配置例子请看etc/jetty-rewrite.xml。
下面是嵌入Jetty的一个例子,和上面的配置文件做同样的事情:
Server server = new Server(); RewriteHandler rewrite = new RewriteHandler(); rewrite.setRewriteRequestURI(true); rewrite.setRewritePathInfo(false); rewrite.originalPathAttribute("requestedPath"); RedirectPatternRule redirect = new RedirectPatternRule(); redirect.setPattern("/redirect/*"); redirect.setReplacement("/redirected"); rewrite.addRule(redirect); RewritePatternRule oldToNew = new RewritePatternRule(); oldToNew.setPattern("/some/old/context"); oldToNew.setReplacement("/some/new/context"); rewrite.addRule(oldToNew); RewriteRegexRule reverse = new RewriteRegexRule(); reverse.setRegex("/reverse/([^/]*)/(.*)"); reverse.setReplacement("/reverse/$2/$1"); rewrite.addRule(reverse); server.setHandler(rewrite);
有几种不同类型的rules。
用servlet模式语法匹配请求的URI。
CookiePatternRule
增加一个cookie到响应。
HeaderPatternRule
增加/修改响应中的header。
RedirectPatternRule
重定向响应。
ResponsePatternRule
发送响应码(status或者error)。
RewritePatternRule
重写URI。
用正则表达式匹配请求URI。
RedirectRegexRule
重定向响应。
RewriteRegexRule
重写URI
匹配请求headers。匹配或者在一个header名称+特定的值,或者在一个header的存在(加任何值)。
ForwardedSchemaHeaderRule
设置请求的计划(scheme)(默认是https)。
其它较为古怪的规则。
MsieSslRule
对IE5和IE6禁用为SSL保持活跃。
LegacyRule
实现RewriteHandler的遗留API。
将rules组织在一起。
VirtualHostRuleContainer
包含的rules仅应用到一个特定的虚拟主机或者一套虚拟主机。
handler是处理请求的Jetty组件。
一些Jetty用户从不需要写Jetty handler,而是使用Servlet API(http://download.eclipse.org/jetty/stable-9/xref/org/eclipse/jetty/servlet/package-summary.html)。你能重用已经存在的Jetty handlers,为上下文、安全、sessions和servlets,不需要任何扩展。然而,一些用户可能有特殊的需求或者担心足迹问题而禁用完整的servlet API。为他们实现一个Jetty handler是一种直截了当的方法,用最小的改动提供动态web内容。
Handler接口提供了Jetty内容产生和处理的核心。实现这个接口的类被用于协调请求、过滤请求和产生内容。
Handler接口的核心API是:
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
这个方法的实现能处理一个请求、传递请求到另一个handler(或servlet)、或者它能修改和/或包装请求,然后传递它。存在三种类型的handler:
1)协调Handlers:传递请求到其它handlers(HandlerCollection、ContextHandlerCollection);
2)过滤Handlers:放大一个请求,然后传递它到其它handlers(HandlerWrapper, ContextHandler, SessionHandler);
3)产生Handlers:产生内容(ResourceHandler和ServletHandler)。
一个handler的目标是处理请求的资源的标识符。这通常是来自一个HTTP请求的URI。然而,在下面两种环境下目标可以不同于请求的URI:
1)如果请求被分发到一个命令的资源,例如一个命名的servlet,目标是那个资源的名称;
2)如果请求是通过请求调度程序,目标是包含的资源的URI,不同于真正请求的URI。
处理方法的签名中使用的请求和响应对象是Servlet Request和Servlet Response。这些是标准的API。更经常的是,进入这些类的Jetty实现被要求:Request和Response。然而,由于请求和响应可以被handlers、filters和servlets包装,直接地传递实现是不可能的。下面的方法用于获取任何包装器下的核心实现对象:
Request base_request = request instanceof Request ? (Request)request : HttpConnection.getCurrentConnection().getRequest(); Response base_response = response instanceof Response ? (Response)response : HttpConnection.getCurrentConnection().getResponse();
注意如果handler传递请求到另一个handler,他应该用request/response对象传递,不使用基础对象。这是为了保留被上游handlers做的封装。
分发参数展示了调用处理的状态,可以为:
1)REQUEST == 1:从一个连接器收到的原始请求;
2)FORWARD == 2:被一个RequestDispatcher前转的请求;
3)INCLUDE == 4:被一个RequestDispatcher包括的请求;
4)ERROR == 8:被容器前转到一个error handler的请求。
这些对大部分的servlet和相关的handlers都是有意思的。例如,安全handler仅对REQUEST分发应用认证和授权。
一个Handler可以处理一个请求通过:
1)产生一个响应;
2)过滤请求和/或响应;
3)传递请求和响应到另一个Handler。
下面具体讲述。
OneHandler展示了怎么产生一个响应。
你能用通常的servlet响应API,通常将设置一些状态、内容headers、然后输出内容:
response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println("<h1>Hello OneHandler</h1>");
handler需要标注它完成了对请求的处理,请求不应该被传递到其它handlers了:
Request base_request = (request instanceof Request) ? (Request)request:HttpConnection.getCurrentConnection().getRequest(); base_request.setHandled(true);
一旦基础请求或响应对象被获取,你就能修改它。一般你将做修改以完成:
1)拆分URI到contextPath、servletPath和pathInfo组件;
2)为静态内容将请求和资源相关联;
3)将请求和session相关联;
4)将请求和安全主体相关联;
5)在请求分发到另一个资源期间改变URI和路径。
你也能更新请求的上下文:
1)设置当前线程上下文类加载器;
2)设置线程局部变量来表示当前ServletContext。
通常Jetty传递一个已修改的请求到另一个handler,并在finally块只能够还原修改:
try { base_request.setSession(a_session); next_handler.handle(target,request,response,dispatch); } finally { base_request.setSession(old_session); }
实现HandlerWrapper类的类是典型的这种类型的handler过滤器。
一个Handler可以简单的视察请求,然后使用目标、请求URI或其它信息以选择另一个Handler作为下一个处理请求的Handler。这些handlers通常实现HandlerContainer接口。
例子包括:
Class Handler Collection
HandlerList
ContextHandlerCollection
看Jetty Latest Source XRef和Jetty Latest JavaDoc获取每一个Jetty Handler的详细信息。
更多Jetty资料请看Jetty总览。