http://datalab.int-yt.com/archives/27
在使用多种服务器程序部署不同的应用的时候可能会遇到多个服务都想使用默认的80端口的情况。但是多个服务器不可能同时占用同一个端口。一般解决这种问题的方法就是使用反向代理。
反向代理有,加密和SSL加速,负载均衡,缓存静态内容,压缩,减速上传,安全,外网发布等功能。
我们使用反向代理只用到了外网发布的作用,应该是最简单的一种反向代理了。目前比较流行的是使用nginx搭建反向代理,但是由于我们的80端口已经被tomcat占住了,而且不能轻易动,因此我才重新寻找能够基于tomcat的反向代理,这样仅仅相当于部署一个应用。
搜了一下,tomcat推荐了http://wiki.apache.org/tomcat/ServletProxy 看起来j2ep是最像样的,其它两个看了介绍就没兴趣了,所以直接下载了j2ep。
看文档介绍j2ep还是比较有好的,只需要修改/WEB-INF/config/data.xml文件就能添加需要代理的服务器,可以实现负载均衡,限制访问,重写网页内容等功能,而且规则比较强大,多种规则可以进行合并。作者想实现静态缓存、ssl加密等功能但是发布1.0之后似乎作者就没有继续写下去。
实际试了一下果然是不够完善,爆出了各种问题,不得不进行修改:
- 无法代理中文…… 解决方案,修改UrlRewritingOutputStream类中的rewrite方法
12345
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方法
12345678910111213141516
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();
}
- 反向代理再反向代理遇到的问题…… 好吧,这个是个奇葩的问题,正常人都不这么干。但是这的确是个问题,作者本身估计也没想到。如果再加一层反向代理可能会使页面都无法显示,这个对j2ep来说应该不是个错误,因为j2ep返回的内容浏览器是认识的,但是header里多了一个transfer-encoding,这会造成下一个反向代理服务器出错。因此应该去掉原始服务器带出来的transfer-encoding。解决方案,修改ResponseHandlerBase中setHeaders方法
1234567891011121314
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 1234567891011public
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