HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议,JAVA可以使用HttpClient的Jar包实现模拟登陆。今天尝试登陆一下辽宁大学的选课系统。
通过页面分析得知登陆采用Post方式,表单发送到http://jwgl.lnu.edu.cn/pls/wwwbks/bks_login2.login
,
参数名分别是stuid
和pwd
。
下面开始编写工具类
一、实现思路
创建HttpClient默认实例
CloseableHttpClient httpClient = HttpClients.createDefault();
创建HttpPost实例
HttpPost httpPost = new HttpPost(URL);
如果是Get方法则创建HttpGet实例,二者构造函数参数都可以为目标地址。
创建HttpEntity实例:
StringEntity stringEntity = new StringEntity(param, "UTF-8");
stringEntity.setContentType("application/x-www-form-urlencoded");
Http消息(请求或者响应)会携有Http实体,Http实体可以解析为文本形式,也可以将文本转换为Http实体,无论解析还是转换都要约定字符编码。
Post请求的参数也可以被写入Http实体中,其格式为:
key1=value1&key2=value2
ContentType内容类型,用于定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件,通常Post表单内容类型默认为application/x-www-form-urlencoded
更多内容类型参照:
HTTP Content-type 对照表
http://tool.oschina.net/commons
创建RequstConfig实例:
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(15000)
.setConnectTimeout(15000)
.setConnectionRequestTimeout(15000)
.build();
通常利用requestConfig设置超时时间。
将配置好的HttpEntity与RequestConfig实例设置到HttpPost
httpPost.setEntity(stringEntity);
httpPost.setConfig(requestConfig);
用HttpClient实例执行HttpPost,返回Response。
CloseableHttpResponse response = httpClient.execute(httpPost);
httpClient.execute()方法也适用于HttpGet,会返回一个CloseableHttpResponse对象,里面封装有HttpEntity
从Response获取Entity,得到访问信息
我们可以通过response实例中的getEntity()方法获得httpEntity
HttpEntity httpEntity = response.getEntity();
如果想得到网页源文件,则利用EntityUtils.toString()将实体解析成字符串。
String responseContent = EntityUtils.toString(httpEntity , "UTF-8");
关闭资源
response.close();
httpClient.close();
完整源码
package test;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.util.EntityUtils;
public class FunctionClass {
/**
* sendPost 发送post请求
* @param url
* @param param
* @return
* @throws IOException
*/
public String sendPost(String url, String param) throws IOException {
String result = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
try {
HttpPost hp = new HttpPost(url);
//配置ResquestConfig
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(15000)
.setConnectTimeout(15000)
.setConnectionRequestTimeout(15000)
.build();
//配置StringEntity
StringEntity stringEntity = new StringEntity(param, "UTF-8");
stringEntity.setContentType("application/x-www-form-urlencoded");
//将Entity和Config设置到HttpPost
hp.setEntity(stringEntity);
hp.setConfig(requestConfig);
//获取页面
response = httpClient.execute(hp);
result = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();// TODO: handle exception
}finally{
httpClient.close();
response.close();
}
return result;
}
}
二、测试一下
编写测试类
package test;
import java.io.IOException;
public class TestClass {
public static void main(String[] args) {
//http://jwgl.lnu.edu.cn/pls/wwwbks/bks_login2.login?stuid=161407212&pwd=058512
FunctionClass fc = new FunctionClass();
try {
String result = fc.sendPost("http://jwgl.lnu.edu.cn/pls/wwwbks/bks_login2.login", "stuid=XXXXXX&pwd=YYYYY");
System.out.println("返回的结果是:");
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行调试
运行发现出现了问题
并没有返回正确的页面信息,而仅仅返回一个换行符,让我们来通过response的getStatusLine()方法看一下问题出在哪里。
System.out.println(response.getStatusLine());
原来这里出现了302 Found错误。
三、302 Found
关于302 Found:
302 Found 是HTTP协议中的一个状态码(Status Code),可以简单的理解为该资源原本确实存在,但已经被临时改变了位置;或者换个说法,就是临时的存在于某个临时URL下。
也就是说Servlet可能发生了重定向,通常Get或者Head会自动转向重定向的网页,但是Post和Push方法是被禁止的。
解决方案
其中一个办法是采用Get方法代替Post,但是Get和Post本身就是两个东西,不是所有网页都可以这样。
第二个方法是改变HttpClient的重定向策略
将
CloseableHttpClient httpClient = HttpClients.createDefault();
改为
CloseableHttpClient httpClient = HttpClients.custom()
.setRedirectStrategy(new LaxRedirectStrategy())
.build();
LaxRedirectStrategy可实现HEAD, GET, POST, 和DELETE方法自动重定向,可以借此解除HTTP规定的对POST方法自动重定向的限制
第二次运行调试
已经可以登录成功,并且争取获取页面源文件了,初步战略目标达成。
三、总结与反思
HttpClient完善且强大,模拟登录还不算彻底成功,需要学习的还有很多,同时编写代码还不够规范,没有养成良好的习惯。希望可以通过写博文彻底治愈懒癌,使自己每天进步一点点!