httpClient释放链接的问题

nice_so 发布于 2013/10/11 17:16
阅读 46K+
收藏 2

开源之夏第三届火热来袭,高校学生参与赢万元奖金!>>>

昨天接触到了httpclient和jsoup,

使用httpclient模拟登陆OA,想抓OA的数据下来,无实在意义,只是练手。

不过在过程中出了一点问题。

public static boolean login(){
		HttpGet get = new HttpGet(uri+"/logincheck.php");
		List<NameValuePair> params = new ArrayList<NameValuePair>();
		//....
		try {
			String str = EntityUtils.toString(new UrlEncodedFormEntity(params));
			get.setURI(new URI(get.getURI()+"?"+str));
			response = client.execute(get);
			//....
		} catch (Exception e) {
			e.printStackTrace();
		}
		if(response.getStatusLine().getStatusCode()==200){
			System.out.println("登陆成功!");
			return true;
		}else{
			return false;
		}
	}
这个方法没有问题,不过在登陆之后,我直接访问一个OA里面的新闻页面,去抓数据的时候就会出错。

public static String getNewsContent(){
		HttpGet get = new HttpGet(uri+"/general/notify/show");
		try {
			response = client.execute(get);
			HttpEntity entity = response.getEntity();
			String newsContent = EntityUtils.toString(entity);
			Document doc = Jsoup.parse(newsContent);
			Elements elements = doc.getElementsByClass("TableLine1");
			for(Element element : elements){
				System.out.println(element.val());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}
在第二次client.execute(get)的时候就会报错。

java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

加载中
0
guor
guor

引用来自“lietome”的答案

提示很明确,你没有释放连接,我在官方的Samples里面找到一段代码应该可以帮助你

CloseableHttpClient httpclient = HttpClients.createDefault();
try {
	HttpGet httpget = new HttpGet("http://www.apache.org/");
	// Execute HTTP request
	CloseableHttpResponse response = httpclient.execute(httpget);
	try {
		// Get hold of the response entity
		HttpEntity entity = response.getEntity();
		// If the response does not enclose an entity, there is no need
		// to bother about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			try {
				instream.read();
				// do something useful with the response
			} catch (IOException ex) {
				// In case of an IOException the connection will be released
				// back to the connection manager automatically
				throw ex;
			} finally {
				// Closing the input stream will trigger connection release
				instream.close();
			}
		}
	} finally {
		response.close();
	}
} finally {
	httpclient.close();
}
有几种方式,第一种类似长连接,个人非常不喜欢这个,参考 http://hc.apache.org/httpcomponents-client-4.3.x/tutorial/html/connmgmt.html,第二中方式是使用Cookies,浏览器不就是这么做的么,参考 http://hc.apache.org/httpcomponents-client-4.3.x/tutorial/html/statemgmt.html,官方文档都有说明哈
1
司马建邺
司马建邺

引用来自“徐春鹏”的答案

引用来自“名字是什么能吃吗”的答案

请求结束后调用get.abort或者EntityUtils.consume试试
这个就成吧 忽略内容
@nice_so  : client= new DefaultHttpClient();
try {
HttpResponse execute = client.execute(new HttpGet(GetConfig
.getValue("login_url")));
EntityUtils.consume(execute.getEntity());
CookieStore cookieStore = client.getCookieStore();
List<Cookie> cookies = cookieStore.getCookies();

} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
这样能获得cookie 保存起来就行了 ;如果不再去new一个HttpClient新对象的话httpclient不用去刻意保存cookie, 登录成功后 ,直接拿这个client去get post 其他地址就行
0
名字是什么能吃吗
名字是什么能吃吗
请求结束后调用get.abort或者EntityUtils.consume试试
nice_so
nice_so
不行的,会报错,就是上面的那个错误。 可以看我上面的代码,就是你说的那样
名字是什么能吃吗
名字是什么能吃吗
回复 @nice_so : 用发登录请求的HttpClient对象再次请求就行啊
nice_so
nice_so
我的意思是在 第一次请求结束后,怎么保持登录状态进行第二次请求。 就像用户登录了之后进行操作一样。
0
终曲
终曲
不知道你用的哪个版本,4.x之后改动挺多的,和你这个问题相关的比如PoolingClientConnectionManager代替了ThreadSafeClientConnManager、EntityUtils.consume代替了consumeContent ,用连接池维护或者每次打开entity之后consume
终曲
终曲
回复 @nice_so : consume又不是释放连接,销毁你打开的entity而已,你的client还是那个就行
nice_so
nice_so
我的意思是在 第一次请求结束后,怎么保持登录状态进行第二次请求。 释放连接,第二次请求的时候又没登录, 不释放连接,就又报上面的错误。 就像用户登录了之后进行操作一样。
0
guor
guor

提示很明确,你没有释放连接,我在官方的Samples里面找到一段代码应该可以帮助你

CloseableHttpClient httpclient = HttpClients.createDefault();
try {
	HttpGet httpget = new HttpGet("http://www.apache.org/");
	// Execute HTTP request
	CloseableHttpResponse response = httpclient.execute(httpget);
	try {
		// Get hold of the response entity
		HttpEntity entity = response.getEntity();
		// If the response does not enclose an entity, there is no need
		// to bother about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			try {
				instream.read();
				// do something useful with the response
			} catch (IOException ex) {
				// In case of an IOException the connection will be released
				// back to the connection manager automatically
				throw ex;
			} finally {
				// Closing the input stream will trigger connection release
				instream.close();
			}
		}
	} finally {
		response.close();
	}
} finally {
	httpclient.close();
}

nice_so
nice_so
那怎么让程序记住自己的登录状态,继而去请求下一个需要登录才能请求的页面呢
guor
guor
回复 @nice_so : 两个请求就得用两个连接,如何连接的是httpclient封装在内部的,外部不做此控制,就像你用普通jsp请求一样,你面向的是一次次的请求,而不是连接,而且每次请求必须释放,不然端口一直占用着
nice_so
nice_so
我的意思是在 第一次请求结束后,怎么保持登录状态进行第二次请求。 释放连接,第二次请求的时候又没登录, 不释放连接,就又报上面的错误。 就像用户登录了之后进行操作一样。
0
司马建邺
司马建邺

引用来自“名字是什么能吃吗”的答案

请求结束后调用get.abort或者EntityUtils.consume试试
这个就成吧 忽略内容
nice_so
nice_so
我的意思是在 第一次请求结束后,怎么保持登录状态进行第二次请求。 释放连接,第二次请求的时候又没登录, 不释放连接,就又报上面的错误。 就像用户登录了之后进行操作一样。
0
s
snowclod

感谢答主,碰到同样的问题,我这边关闭response就行了

0
阳光刚刚好
阳光刚刚好

http请求都是分开请求的,但是两个http请求可以共用一个Socket连接

你需要的解决的是,怎么在第二次请求的时候,带上第一次请求返回的sessionid

OSCHINA
登录后可查看更多优质内容
返回顶部
顶部