HttpClient简介
一、简介
超文本传输协议(HTTP)是目前互联网上使用的最重要的协议,尽管java.net
包中提供了通过HTTP访问资源的基本功能,但它并没有提供出许多应用程序所需的全部灵活性或功能。HttpClient试图通过提供一个实现了最新HTTP标准和建议的高效且功能丰富的客户端包,从而填补这一空白。
二、下载与安装
可以下载HttpClient及其依赖的jar或者添加Maven依赖:
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
三、基本用法
1、术语介绍
- HTTP Message
HTTP消息由头部分和可选实体组成,共有两种消息:请求和响应。它们在第一行的格式上有所不同,但都可以有头字段和可选的实体。
- HTTP Request
HTTP请求是从客户端发送到服务器的消息,第一行包括发送请求的URI和服务器应该为客户机执行的方法。
- HTTP Response
HTTP响应是从服务器发送到客户端的响应消息,第一行包含一个状态代码,用于告知请求的成功或失败。
HTTP定义了一组状态代码,比如200表示成功,404表示未找到。
- Method
方法是服务器请求的操作,HTTP定义了一组操作,最常见的是GET和POST。
- Header Fields
头字段是name-value
对,其中名称和值都是文本;头字段的名称不区分大小写;可以将多个值分配给同一个名称。
- Entity
实体是通过HTTP消息发送的数据。例如,响应可以包含作为实体正在下载的页面或图像;请求可以包含在Web表单中输入的参数。
HTTP消息的实体可以具有任意的数据格式,这种格式通常在头字段中指定为MIME类型。
- Session
会话是从单个源到服务器的一系列请求;服务器可以保存会话数据,并且需要识别每个传入请求所属的会话。
- Cookies
Cookies是服务器跟踪会话的首选方式。服务器响应请求提供一段称为cookie的数据,服务器期望客户端在头字段中发送该数据块,并在同一会话的每个请求之后发送该数据块。
每个会话的cookie是不同的,因此服务器可以通过查看cookie来标识请求属于哪个会话。如果请求中缺少cookie,那么服务器将不会按预期响应。
2、执行Get请求
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://localhost:8080/StudySpringMVC/getUser");
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity);
} finally {
response.close();
}
3、执行Post请求
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://localhost:8080/StudySpringMVC/greeting");
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("name", "albert"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response = httpclient.execute(httpPost);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity);
} finally {
response.close();
}
四、样例
样例中使用了httpbin.org
,它是一个简单的HTTP请求和响应服务。
1、响应处理
此样例演示如何使用响应处理程序处理HTTP响应,这是执行HTTP请求和处理HTTP响应的推荐方法。这种方法使调用方能够专注于处理HTTP响应的过程,并将系统资源释放任务委托给HttpClient。使用HTTP响应处理程序可以保证在所有情况下,底层的HTTP连接都会被自动释放回连接管理器。
public class ClientWithResponseHandler {
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
HttpGet httpGet = new HttpGet("https://jsonplaceholder.typicode.com/users/1");
System.out.println("Executing request " + httpGet.getRequestLine());
//Create a custom response handler
ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if(status >= 200 && status < 300){
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
}else {
throw new ClientProtocolException("Unexpected response status: " + status);
}
}
};
String responseBody = httpClient.execute(httpGet, responseHandler);
System.out.println("----------------------------------------");
System.out.println(responseBody);
}finally{
httpClient.close();
}
}
}
2、手动释放连接
此样例演示了如何在手动处理HTTP响应的情况下,确保将底层HTTP连接释放回连接管理器。
public class ClientConnectionRelease {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
HttpGet httpGet = new HttpGet("http://httpbin.org/get");
System.out.println("Executing request " + httpGet.getRequestLine());
CloseableHttpResponse response = httpClient.execute(httpGet);
try{
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
//响应实体
HttpEntity entity = response.getEntity();
//如果响应未包含实体,则无需为连接释放而烦恼
if(entity != null){
InputStream inStream = entity.getContent();
try{
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while((len = inStream.read(buffer)) != -1){
result.write(buffer, 0, len);
}
System.out.println(result.toString("UTF-8"));
}catch(IOException ex){
//如果发生IOException,则连接将被释放自动返回到连接管理器
throw ex;
}finally{
//关闭输入流将触发连接释放
inStream.close();
}
}
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
}
3、中止请求
此样例演示如何在HTTP请求正常完成之前中止该请求。
public class ClientAbortMethod {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
HttpGet httpGet = new HttpGet("http://httpbin.org/get");
System.out.println("Executing request " + httpGet.getURI());
CloseableHttpResponse response = httpClient.execute(httpGet);
try{
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
//不想处理响应正文,在请求对象上调用中止
httpGet.abort();
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
}
4、客户端认证
此样例使用HttpClient对需要用户身份验证的目标站点执行HTTP请求。
需要身份验证的站点:
public class ClientAuthentication {
public static void main(String[] args) throws Exception{
CredentialsProvider provider = new BasicCredentialsProvider();
AuthScope authscope = new AuthScope("httpbin.org", 80);
Credentials credentials = new UsernamePasswordCredentials("user", "passwd");
provider.setCredentials(authscope, credentials);
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(provider).build();
try{
HttpGet httpGet = new HttpGet("http://httpbin.org/basic-auth/user/passwd");
CloseableHttpResponse response = httpClient.execute(httpGet);
try{
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
}
5、使用代理
此样例演示了如何通过代理发送HTTP请求。
public class ClientExecuteProxy {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
HttpHost target = new HttpHost("httpbin.org", 443, "http");
HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");
RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
HttpGet request = new HttpGet("/");
request.setConfig(config);
System.out.printf("Executing request %s to %s via %s.", request.getRequestLine(), target, proxy);
CloseableHttpResponse response = httpClient.execute(target, request);
try{
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
}
6、代理认证
此样例演示通过认证代理隧道的安全连接执行HTTP请求。
public class ClientProxyAuthentication {
public static void main(String[] args) throws Exception{
String targetHost = "httpbin.org";
int targetPort = 80;
String proxyHost = "localhost";
int proxyPort = 8080;
CredentialsProvider provider = new BasicCredentialsProvider();
AuthScope authscope = new AuthScope(proxyHost, proxyPort);
Credentials credentials = new UsernamePasswordCredentials("squid", "squid");
provider.setCredentials(authscope, credentials);
authscope = new AuthScope(targetHost, targetPort);
credentials = new UsernamePasswordCredentials("user", "passwd");
provider.setCredentials(authscope, credentials);
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(provider).build();
try{
HttpHost target = new HttpHost(targetHost, targetPort);
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
HttpGet request = new HttpGet("/basic-auth/user/passwd");
request.setConfig(config);
System.out.printf("Executing request %s to %s via %s.", request.getRequestLine(), target, proxy);
CloseableHttpResponse response = httpClient.execute(target, request);
try{
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
}
7、块编码的POST请求
此样例演示如何使用块编码流式传输请求实体。
public class ClientChunkEncodedPost {
public static void main(String[] args) throws Exception{
String filePath = "D:/Temp/movie/readme.txt";
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
HttpPost request = new HttpPost("http://httpbin.org/post");
File file = new File(filePath);
//使用InputStreamEntity能够从任意来源中流式传输数据,此处也可以使用FileEntity
//FileEntity entity = new FileEntity(file, "binary/octet-stream");
InputStreamEntity entity = new InputStreamEntity(
new FileInputStream(file), -1, ContentType.APPLICATION_OCTET_STREAM);
entity.setChunked(true);
request.setEntity(entity);
System.out.println("Executing request: " + request.getRequestLine());
CloseableHttpResponse response = httpClient.execute(request);
try{
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
}
8、自定义执行上下文
此样例演示如何使用填充了自定义属性的本地HTTP上下文。
public class ClientCustomContext {
public static void main(String[] args) throws Exception{
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
CookieStore cookieStore = new BasicCookieStore();
cookieStore.addCookie(new BasicClientCookie("uid", "666666"));
HttpClientContext clientContext = HttpClientContext.create();
clientContext.setCookieStore(cookieStore);
HttpGet request = new HttpGet("http://httpbin.org/cookies");
System.out.println("Executing request " + request.getRequestLine());
CloseableHttpResponse response = httpClient.execute(request, clientContext);
try{
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
List<Cookie> cookies = cookieStore.getCookies();
for(int i = 0; i < cookies.size(); i++){
System.out.println("Local cookie: " + cookies.get(i));
}
EntityUtils.consume(response.getEntity());
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
}
9、基于表单的登录
此样例演示如何使用HttpClient执行基于表单的登录。
public static void main(String[] args) throws Exception{
CookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
try{
HttpGet request = new HttpGet("http://localhost:8080/StudySpringMVC/index");
CloseableHttpResponse response = httpClient.execute(request);
try{
HttpEntity entity = response.getEntity();
System.out.println("Login form get: " + response.getStatusLine());
EntityUtils.consume(entity);
System.out.println("Initial set of cookies:");
printCookies(cookieStore.getCookies());
}finally{
response.close();
}
HttpUriRequest login = RequestBuilder.post()
.setUri(new URI("http://localhost:8080/StudySpringMVC/greeting"))
.addParameter("name", "albert")
.addParameter("passwd", "666666")
.build();
response = httpClient.execute(login);
try{
HttpEntity entity = response.getEntity();
System.out.println("Login form get: " + response.getStatusLine());
EntityUtils.consume(entity);
System.out.println("Post logon cookies:");
printCookies(cookieStore.getCookies());
}finally{
response.close();
}
}finally{
httpClient.close();
}
}
public static void printCookies(List<Cookie> cookies){
if(cookies.isEmpty()){
System.out.println("Cookies is none!");
}else{
for(int i = 0; i < cookies.size(); i++){
System.out.println("- " + cookies.get(i).toString());
}
}
}
客户端输出:
Login form get: HTTP/1.1 200 OK
Initial set of cookies:
- [version: 0][name: JSESSIONID][value: F8B0CA3D8CDC4B159D72EFA024359A14][domain: localhost][path: /StudySpringMVC/][expiry: null]
Login form get: HTTP/1.1 200 OK
Post logon cookies:
- [version: 0][name: JSESSIONID][value: F8B0CA3D8CDC4B159D72EFA024359A14][domain: localhost][path: /StudySpringMVC/][expiry: null]
更多样例请参考官网样例。