/* ==================================================================
* Created [2009-4-27 下午11:32:55] by Jon.King
* ==================================================================
* TSS
* ==================================================================
* mailTo:jinpujun@hotmail.com
* Copyright (c) Jon.King, 2009-2012
* ==================================================================
*/
package com.jinhe.tss.core.web.rmi;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import com.jinhe.tss.core.exception.BusinessServletException;
import com.jinhe.tss.core.sso.appserver.AppServer;
import com.jinhe.tss.core.sso.context.Context;
import com.jinhe.tss.core.sso.context.RequestContext;
import com.jinhe.tss.core.web.RewriteableHttpServletRequest;
/**
* <p> HttpClientHelper.java </p>
*
*/
public class HttpClientHelper {
private HttpClientHelper() { }
private static HttpClientHelper helper;
public static HttpClientHelper instance(){
if(helper == null){
helper = new HttpClientHelper();
}
return helper;
}
/** 请求超时时间(毫秒数) */
public static final int HTTP_REQUEST_TIMEOUT = 30000; // 30秒
/** Post请求时,Method值 */
public static final String POST_METHOD = "POST";
/** HTTP请求类型参数名 */
public static final String CONTENT_TYPE = "Content-Type";
/**
* <p>
* 初始化HttpClient对象
* </p>
* @return
*/
public HttpClient getHttpClient() {
HttpClient client = new HttpClient();
// 设置Cookie处理策略,RFC_2109是支持较普遍的一个,还有其他cookie协议
client.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
// 设置超时时间
MultiThreadedHttpConnectionManager hcm = new MultiThreadedHttpConnectionManager();
hcm.getParams().setConnectionTimeout(HTTP_REQUEST_TIMEOUT);
client.setHttpConnectionManager(hcm);
return client;
}
/**
* <p>
* 初始化HttpClient对象,同时设置转发应用的Cookie信息。
* 将当前请求中的cookie信息(除去sessionId cookie 和 token cookie)设置到新的请求中来
* </p>
* @param targetAppServer 转发的目标应用
* @return
*/
public HttpClient getHttpClient(AppServer targetAppServer) {
HttpState initialState = new HttpState();
HttpServletRequest request = Context.getRequestContext().getRequest();
javax.servlet.http.Cookie[] cookies = request.getCookies();
if (cookies != null) {
// 设置转发Cookies信息
AppServer currentAppServer = Context.getApplicationContext().getCurrentAppServer();
for (int i = 0; i < cookies.length; i++) {
String cookieName = cookies[i].getName();
if (cookieName.equals(currentAppServer.getSessionIdName()) || cookieName.equals(RequestContext.USER_TOKEN)) {
continue;
}
//保存当前应用以为得sessionId信息的cookie一般是以其应用Code命名的,当前应用的则以JSESSIONID命名
if (cookieName.equals(targetAppServer.getCode())) {
cookieName = targetAppServer.getSessionIdName();
}
Cookie cookie = new Cookie(targetAppServer.getDomain(), cookieName, cookies[i].getValue(),
targetAppServer.getPath(), null, request.isSecure());
initialState.addCookie(cookie);
}
}
HttpClient client = this.getHttpClient();
client.setState(initialState);
client.getParams().setParameter("http.protocol.single-cookie-header", targetAppServer.isSingleCookieHeader());
return client;
}
/**
* <p>
* 初始化HttpMethod对象。
* 转发的时候把第一次转发过来header头带的appCode值去掉,理论上不会有二次转发的可能。
* </p>
* @param appServer
* @return
* @throws IOException
* @throws BusinessServletException
*/
public HttpMethod getHttpMethod(AppServer appServer) throws IOException, BusinessServletException {
RequestContext requestContext = Context.getRequestContext();
HttpServletRequest request = requestContext.getRequest();
// 并初始化QueryString参数
String realPath = requestContext.getRealPath();
String queryString = null;
if (realPath == null || "".equals(realPath)) {
realPath = request.getRequestURI().substring(request.getContextPath().length());
queryString = request.getQueryString();
} else {
realPath = URLDecoder.decode(realPath, "UTF-8");
int index = realPath.indexOf("?");
if (index > -1) {
realPath = realPath.substring(0, index);
queryString = realPath.substring(index + 1);
}
}
String newurl = appServer.getBaseURL() + realPath;
// 根据请求类型创建请求代理
HttpMethod httpMethod;
if (POST_METHOD.equalsIgnoreCase(request.getMethod())) { // POST
httpMethod = new PostMethod(newurl);
// 设置请求内容,将原请求中的数据流转给新的请求
InputStreamRequestEntity requestEntity = new InputStreamRequestEntity(request.getInputStream(), request.getContentType());
((PostMethod)httpMethod).setRequestEntity(requestEntity);
} else { // GET
httpMethod = new GetMethod(newurl);
}
// 设置QueryString参数
if (queryString != null && !"".equals(queryString)) {
httpMethod.setQueryString(queryString);
}
// 设置请求头参数
@SuppressWarnings("unchecked")
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String value = request.getHeader(name);
// 转发的时候去掉header中 cookie(下面单独转发) 和 appCode(转发后不再需要)
if ("cookie".equalsIgnoreCase(name) || "appCode".equalsIgnoreCase(name)) continue;
httpMethod.setRequestHeader(name, value);
}
// 设置用户令牌
if (Context.isOnline()){
httpMethod.setRequestHeader(RequestContext.USER_TOKEN, Context.getToken());
}
// 设置客户端IP
httpMethod.setRequestHeader(RequestContext.USER_CLIENT_IP, requestContext.getClientIp());
return httpMethod;
}
/**
* 处理二次转发请求(request2)转发成功后 返回的Cookie信息,将这些cookie设置到初始的请求和响应里
* @param cookies
* 注:是org.apache.commons.httpclient.Cookie
* @param targetAppServer
*/
public static void transmitReturnCookies(org.apache.commons.httpclient.Cookie[] cookies, AppServer targetAppServer) {
RequestContext requestContext = Context.getRequestContext();
if (requestContext == null) { return; }
RewriteableHttpServletRequest request = requestContext.getRequest();
HttpServletResponse response = Context.getResponse();
if (response == null || request == null) { return; }
// 转发返回Cookies
for (int i = 0; i < cookies.length; i++) {
String cookieName = cookies[i].getName();
//如果当前应用本身的cookie,则无需转发
if (cookieName.equals(Context.getApplicationContext().getCurrentAppCode())) continue;
if (cookieName.equals(targetAppServer.getSessionIdName())) {
cookieName = targetAppServer.getCode();
}
javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie(cookieName, cookies[i].getValue());
cookie.setPath(request.getContextPath());
cookie.setMaxAge(-1);
cookie.setSecure(request.isSecure());
if (response.isCommitted()) {
response.addCookie(cookie);
}
request.addCookie(cookie); // 同时也添加到request中,以用于二次、三次的远程接口调用
}
}
}