4.4 HttpClient 用法
4.4.1 HttpClient 简介
尽管 JDK 中有通过 HTTP 访问资源的相关 API,但其功能和灵活性受到限制。HttpClient 隶属于 Apache 的 HttpComponents 项目,它提供了更丰富和更高效的 HTTP 访问方式,主要特点如下。
■ 纯 Java 实现,支持 HTTP 1.1。
■ 支持 HTTPS。
■ 支持通过 CONNECT 方法建立隧道连接。
■ 支持 Basic、Digest 和 NTLM 等鉴权方式。
■ 支持设置连接超时。
■ 源代码基于 Apache 许可协议,因此是免费开源的。
4.4.2 创建工程
在学习 HttpClient 之前,先来创建一个新的 Maven 项目,关键信息填写如下。
Group Id:cn.edu.bjut
Artifact Id:httpinterfacetest
Name:HTTP Interface Test
可根据实际情况填写,不需要和这里填写的内容完全一致。
创建完成后,在 pom.xml 文件的<;name>;标签后输入以下粗体部分内容:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.edu.bjut</groupId> <artifactId>httpinterfacetest</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency> </dependencies> </project>
保存 pom.xml 文件,这时 Maven 会自动下载 HttpClient 及其依赖的其他 jar 包。
4.4.3 发送 HTTP 请求
1.发送 GET 请求
在 src/test/java 中创建名为 cn.edu.bjut.httpinterfacetest 的 Package 及名为 Test 的 Class(需要勾选「public static void main(String[] args)」),在 Test 中输入以下内容:
package cn.edu.bjut.httpinterfacetest; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.net.URI; import java.net.URISyntaxException; public class Test { public static void main(String[] args) { CloseableHttpClient client = HttpClients.createDefault(); HttpGet httpGet1 = new HttpGet("http://localhost:8080/mobilePhone?model=iPhone+6S"); URI uri = null; try { uri = new URIBuilder().setScheme("http").setHost("localhost"). setPort(8080).setPath("/mobilePhone"). setParameter("model", "iPhone 6S").build(); } catch (URISyntaxException e) { e.printStackTrace(); } HttpGet httpGet2 = new HttpGet(uri); CloseableHttpResponse response = null; try { response = client.execute(httpGet1); System.out.println(EntityUtils.toString(response.getEntity())); response = client.execute(httpGet2); System.out.println(EntityUtils.toString(response.getEntity())); } catch (Exception e) { e.printStackTrace(); } } }
如果未在pom.xml里配置,默认使用1.5版本jdk编译。
IDEA Error:java: Compilation failed: internal java compiler error
解决办法很简单:File-->Setting...-->Build,Execution,Deployment-->Compiler-->Java Compiler 设置相应Module的target bytecode version的合适版本(跟你jkd版本一致),这里我改成1.8版本。
保存代码,按快捷键 F11 运行工程,此时 Eclipse 的控制台输出如下:
下面对运行结果进行说明。
① 通过调用 HttpClients 类的静态方法构建一个 HTTP 客户端。
②GET 请求通过实例化 HttpGet 类来实现,其他 HTTP 请求也有相应的类,即 HttpDelete、HttpHead、HttpOptions、HttpPatch、HttpPost、HttpPut 和 HttpTrace。
③ 第一种构建 GET 请求的方式是使用 String,其特点是语法简洁,但结构不是很清晰。第二种构建 GET 请求的方式是使用 URI(Uniform Resource Identifier,即统一资源标识符),其特点是结构清晰,但构建过程较为复杂,且构建过程可能导致 URI 语法异常,这里我们对异常进行了捕获和处理。当遇到空格时,第一种方式需要手动编码(即把空格替换成 + 号),而第二种方式会自动编码。
④ 通过 HTTP 客户端执行请求得到服务器响应,并将响应打印到控制台。
⑤ 发起请求的过程可能导致多种异常,为简明步骤,这里用 Exception 表示,因为 Exception 类为其他几个异常类的父类,这样可避免罗列多个异常类。
2.发送 POST 请求
下面介绍发送 RESTful POST 请求和 SOAP 请求。SOAP 请求是通过 POST 请求发送的,请求体使用 XML 传输数据。
删除 Test 中的内容,输入以下内容:
public class TestPost { public static void main(String[] args) { CloseableHttpClient client = HttpClients.createDefault(); //构建和发送RESTful POST请求 HttpPost rest = new HttpPost("http://localhost:8080/mobilePhone"); StringEntity stringEntity = new StringEntity( "{"brand":"Motorola","model":"moto Z Play","os":"ANDROID"} ", ContentType.APPLICATION_JSON); rest.setEntity(stringEntity); CloseableHttpResponse response = null; try { response = client.execute(rest); System.out.println(EntityUtils.toString(response.getEntity())); } catch (Exception ex) { ex.printStackTrace(); } } }
保存代码,按快捷键 Ctrl+Shift+F10 运行工程,此时 IDEA 的控制台输出如下:
SOAP 请求是通过 POST 请求发送的,请求体使用 XML 传输数据。
保存代码,按快捷键 F11 运行工程,此时 Eclipse 的控制台输出如下:
下面对运行结果进行说明。
① 两种请求均使用 String 的方式构建。
② 由于 SOAP 请求的请求体跨越了多行,故通过加号(+)进行连接。
③ 两种请求均通过 StringEntity 对象给请求设置了请求体和 Content-Type,区别在于,RESTful POST 请求 Content-Type 为 APPLICATION_JSON,而 SOAP 请求 Content-Type 为 TEXT_XML。
4.4.4 处理服务器响应
服务器处理完客户端发来的 HTTP 请求后,会将结果发回给客户端。HTTP 响应由响应行、响应头和响应体组成,而 HTTP 请求也包含三个组成部分,即请求行、请求头和请求体。前面只是将服务器响应的实体转换为字符串并打印到控制台,其实对服务器响应还可以做很多事情。
删除 Test 中的内容,输入以下代码:
package cn.edu.bjut.httpinterfacetest; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; public class TestResponse { public static void main(String[] args) { CloseableHttpClient client = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("http://localhost:8080/mobilePhone?model=iPhone+6S"); CloseableHttpResponse response = null; try{ response = client.execute(httpGet); System.out.println(response.getProtocolVersion()); System.out.println(response.getStatusLine().getStatusCode()); System.out.println(response.getStatusLine().toString()); HttpEntity httpEntity = response.getEntity(); System.out.println(httpEntity.getContentType()); response.close(); }catch (Exception ex) { ex.printStackTrace(); } } }
保存代码,按快捷键 F11 运行工程,此时 Eclipse 的控制台输出如下:
下面对运行结果进行说明。
① 通过服务器响应可以得到协议版本和响应行,通过响应行又可以进一步得到响应码。当然,也可以调用 toString()方法将整个响应行转换为字符串。
② 通过调用 getEntity()方法可以得到响应实体,通过响应实体又可以得到 Content-Type。
③ 最后关闭服务器响应,这里调用了 close()方法。
4.4.5 设置请求头
HttpClient 可以设置请求头。在实际项目中,登录后往往需要将 session 放置在 cookie 中,以供后续接口使用,而 cookie 正是请求头的一部分。
保存代码,按快捷键 F11 运行工程,此时 Eclipse 的控制台输出如下:
从输出中可以看出,HTTP 请求可以通过 addHeader()方法设置请求头,通过 getAllHeaders()方法获取所有请求头(用一个请求头数组表示)。