httpclient 多线程与cookie

HttpClient4.2之后,PoolingClientConnectionManager说是实现了池的连接管理,也是线程安全的,这个对于cookie来说则不是。

 

场景:

请求同一个链接,但是需要以不同的session 来请求,那么使用PoolingClientConnectionManager产生的同一个httpclient去访问,会使用相同的cookie。

PoolingClientConnectionManager connManager = new PoolingClientConnectionManager(
				registry);

		httpClient = new DefaultHttpClient(connManager, params);

		return httpClient;

向上面的代码,一般是公用这个httpclient, 这样做对于cookie来说就不是多线程安全的了。即使你每次设置了cookie header,也是存在这个问题。这个并不是PoolingClientConnectionManager的原因,而是共用了httpclient造成的。

 

解决方案:

使用BasicClientConnectionManager,并且每次都创建httpclient,因为每次都创建httpclient,当然就没必要使用复杂的PoolingClientConnectionManager。

 

每次登录请求后response.getHeaders("Set-Cookie");获得cookie Header[]

再次请求时将cookie 加入请求header即可。

 

上面的方法对于一般场景可以,但是今天我测试登陆j_spring_security_check这样的验证则不行,还是参照这里

http://codeblow.com/questions/how-do-you-connect-with-an-online-url-which-requires-spring-security/

其窍门是,先要获取一次取得原始cookie,然后第二次请求登陆链接,传入登陆参数,第三次再请求要访问的页面。这三次请求要使用同一个httpclient(非poolmanager)。

 

我作了修改写了个公用函数,考虑到有些情况需要登出,在完成获取数据后再登出,一共是四步,真是纠结的方案……

 

public static String getWithLogin(String loginUrl,String url,String logoutUrl,Map map) {
		DefaultHttpClient httpclient = (DefaultHttpClient) HttpClientUtils
				.getHttpClient(true);
		try {
			//init cookie
			HttpGet httpget = new HttpGet(url);
	        HttpResponse httpClientResponse = httpclient.execute(httpget);
	        HttpEntity entity = httpClientResponse.getEntity();
	        EntityUtils.consume(entity);
	        
			//login
			HttpPost httppost = new HttpPost(loginUrl);

			// Prepare post parameters
			if (null != map && !map.isEmpty()){
				Iterator it = map.entrySet().iterator();

				List<NameValuePair> params = new LinkedList<NameValuePair>();

				while (it.hasNext()) {
					Map.Entry en = (Map.Entry) it.next();
					if (null == en.getValue()) {
						continue;
					}
					String key = en.getKey().toString();
					String value = en.getValue().toString();
					params.add(new BasicNameValuePair(key, value));
				}
				httppost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
			}

			httpClientResponse = httpclient.execute(httppost);
			//check if logined
			

			// check response body
			entity = httpClientResponse.getEntity();
			String result = EntityUtils.toString(entity);
			EntityUtils.consume(entity);
			int statusCode = httpClientResponse.getStatusLine().getStatusCode();
			if (200 != statusCode && 302 != statusCode){
				throw new RuntimeException(statusCode + ":" + result);
			}

			//get data
			httpget = new HttpGet(url);
			httpClientResponse = httpclient.execute(httpget);
			entity = httpClientResponse.getEntity();

			result = EntityUtils.toString(entity);
			EntityUtils.consume(entity);
			statusCode = httpClientResponse.getStatusLine().getStatusCode();
			
			//logout
			if (null != logoutUrl){
				try {
					httpget = new HttpGet(logoutUrl);
					httpClientResponse = httpclient.execute(httpget);
					entity = httpClientResponse.getEntity();

					EntityUtils.consume(entity);
				} catch (Exception e) {
					Log.warn(e,"log out fail to" + logoutUrl);
				}
			}
						
			if (200 != statusCode){
				throw new RuntimeException(statusCode + ":" + result);
			}			
			
			
			return result;
		} catch (Exception e) {
			throw ExceptionUtils.silence(e);
		} finally {
			httpclient.getConnectionManager().shutdown();
		}

	}

Total views.

© 2013 - 2018. All rights reserved.

Powered by Hydejack v6.6.1