標籤:java jetty web應用 架構
Rewrite Handler
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
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
有幾種不同類型的rules。
PatternRule
用servlet模式文法匹配請求的URI。
CookiePatternRule
增加一個cookie到響應。
HeaderPatternRule
增加/修改響應中的header。
RedirectPatternRule
重新導向響應。
ResponsePatternRule
發送響應碼(status或者error)。
RewritePatternRule
重寫URI。
RegexRule
用Regex匹配請求URI。
RedirectRegexRule
重新導向響應。
RewriteRegexRule
重寫URI
HeaderRule
匹配請求headers。匹配或者在一個header名稱+特定的值,或者在一個header的存在(加任何值)。
ForwardedSchemaHeaderRule
佈建要求的計劃(scheme)(預設是https)。
其它
其它較為古怪的規則。
MsieSslRule
對IE5和IE6禁用為SSL保持活躍。
LegacyRule
實現RewriteHandler的遺留API。
RuleContainer
將rules組織在一起。
VirtualHostRuleContainer
包含的rules僅應用到一個特定的虛擬機器主機或者一套虛擬機器主機。
寫自訂的handlers
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 API
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
一個Handler可以簡單的視察請求,然後使用目標、請求URI或其它資訊以選擇另一個Handler作為下一個處理請求的Handler。這些handlers通常實現HandlerContainer介面。
例子包括:
Class Handler Collection
HandlerList
ContextHandlerCollection
更多Handlers的資訊
看Jetty Latest Source XRef和Jetty Latest JavaDoc擷取每一個Jetty Handler的詳細資料。
更多Jetty資料請看Jetty總覽。
Jetty開發指導:Handlers