http://datalab.int-yt.com/archives/27
在使用多種伺服器程式部署不同的應用的時候可能會遇到多個服務都想使用預設的80連接埠的情況。但是多個伺服器不可能同時佔用同一個連接埠。一般解決這種問題的方法就是使用反向 Proxy。
反向 Proxy有,加密和SSL加速,負載平衡,緩衝靜態內容,壓縮,減速上傳,安全,外網發布等功能。
我們使用反向 Proxy只用到了外網發布的作用,應該是最簡單的一種反向 Proxy了。目前比較流行的是使用nginx搭建反向 Proxy,但是由於我們的80連接埠已經被tomcat佔住了,而且不能輕易動,因此我才重新尋找能夠基於tomcat的反向 Proxy,這樣僅僅相當於部署一個應用。
搜了一下,tomcat推薦了http://wiki.apache.org/tomcat/ServletProxy 看起來j2ep是最像樣的,其它兩個看了介紹就沒興趣了,所以直接下載了j2ep。
看文檔介紹j2ep還是比較有好的,只需要修改/WEB-INF/config/data.xml檔案就能添加需要代理的伺服器,可以實現負載平衡,限制訪問,重寫網頁內容等功能,而且規則比較強大,多種規則可以進行合并。作者想實現靜態緩衝、ssl加密等功能但是發布1.0之後似乎作者就沒有繼續寫下去。
實際試了一下果然是不夠完善,爆出了各種問題,不得不進行修改: 無法代理中文…… 解決方案,修改UrlRewritingOutputStream類中的rewrite方法
| 1 2 3 4 5 |
public void rewrite(Server server) throws IOException { ... matcher.appendTail(page); originalStream.write(String.valueOf(page).getBytes()); } |
cookie問題,j2ep本身是有cookie支援的,但是估計作者僅僅是測試了代理整個網站的情況,並沒有測試代理程式一個部分網站的情況,在data.xml中配置了path後例如(http://datalab.int-yt.com/blog/ 中 /blog 就是path)cookie就不好用了,原因是在set-cookie中的path沒有被正確的替換。解決方案,修改UrlRewritingResponseWrapper中rewriteSetCookie方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
private String rewriteSetCookie(String value) { StringBuffer header = new StringBuffer(); Matcher matcher = pathAndDomainPattern.matcher(value); while (matcher.find()) { if (matcher.group( 1 ).equalsIgnoreCase( "path=" )) { String path = server.getRule().revert(matcher.group( 2 ).replace(server.getPath(),contextPath)); // server.getRule().revert(matcher.group(2)); matcher.appendReplacement(header, "$1" + path + ";" ); } else { matcher.appendReplacement(header, "" ); } } matcher.appendTail(header); log.debug( "Set-Cookie header rewritten \"" + value + "\" >> " + header.toString()); return header.toString(); } |
反向 Proxy再反向 Proxy遇到的問題…… 好吧,這個是個奇葩的問題,正常人都不這麼幹。但是這的確是個問題,作者本身估計也沒想到。如果再加一層反向 Proxy可能會使頁面都無法顯示,這個對j2ep來說應該不是個錯誤,因為j2ep返回的內容瀏覽器是認識的,但是header裡多了一個transfer-encoding,這會造成下一個反向 Proxy伺服器出錯。因此應該去掉原始伺服器帶出來的transfer-encoding。解決方案,修改ResponseHandlerBase中setHeaders方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
protected void setHeaders(HttpServletResponse response) { Header[] headers = method.getResponseHeaders(); for ( int i= 0 ; i < headers.length; i++) { Header header = headers[i]; String name = header.getName(); boolean contentLength = name.equalsIgnoreCase( "content-length" ); boolean connection = name.equalsIgnoreCase( "connection" ); boolean transferEncoding = name.equalsIgnoreCase( "transfer-encoding" ); if (!contentLength && !connection && !transferEncoding) { response.addHeader(name, header.getValue()); } } setViaHeader(response); } |
只能支援html,javascript css中的串連重寫,這個如果要是不止這幾種檔案的串連需要重寫,那麼就得自己動手修改UrlRewritingResponseWrapper中的processStream 、getOutputStream 方法,並且在UrlRewritingOutputStream中添加類似rewrite函數的代碼了。 URL替換竟然只支援帶斜線的。。。
BaseServer.java
| 1 2 3 4 5 6 7 8 9 10 11 |
public Server getServerMapped(String location) { String fullPath = getDomainName() + getPath() + "/" ; if (location.length() < fullPath.length()&&!location.endsWith( "/" )){ location+= '/' ; } if (location.startsWith(fullPath) && isRewriting) { return this ; } else { return null ; } } |
修改後的代碼j2ep