1. 什么是HttpClient
HttpClient是Apache下面的子项目,可以提供高效的,最新的,功能丰富的支持HTTP协议的客户端编程工具包。
2. 为什么要学习HttpClient
- Http协议用的很多,很多程序需要直接通过HTTP协议来访问网络资源。当前大部分项目暴漏出来的接口是Http请求,数据格式是JSON格式。
- 现在流行的SpringCloud服务与服务之间的调用底层就是通过HttpClient技术。
- 可以实现多个系统之间的相互访问。
3. HttpClient 提供的主要的功能
(1)实现了所有 HTTP 的方法(GET,POST,PUT,DELETE 等)
(2)支持自动转向
(3)支持 HTTPS 协议
(4)支持代理服务器等
4. HttpClient的请求类型
其实现了所有的Http请求类型,相应的类为
HttpGet、HttpPost、HttpDelete、HttpPut
5. HttpClient使用流程
(1)创建HttpClient对象。
(2)创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
(3)如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
(4)调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
(5)调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
(6)释放连接。无论执行方法是否成功,都必须释放连接。
6. 发送一个Http请求访问百度试试
转载
大佬地址
详细http的api
api
get请求:
public static void main(String[] args) throws IOException {
//1.打开浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
//2.声明get请求
HttpGet httpGet = new HttpGet("http://www.baidu.com/");
//3.发送请求
CloseableHttpResponse response = httpClient.execute(httpGet);
//4.判断状态码
if(response.getStatusLine().getStatusCode()==200){
HttpEntity entity = response.getEntity();
//使用工具类EntityUtils,从响应中取出实体表示的内容并转换成字符串
String string = EntityUtils.toString(entity, "utf-8");
System.out.println(string);
}
//5.关闭资源
response.close();
httpClient.close();
}
post请求:
public static void main(String[] args) throws IOException {
//1.打开浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
//2.声明get请求
HttpPost httpPost = new HttpPost("https://www.oschina.net/");
//3.开源中国为了安全,防止恶意攻击,在post请求中都限制了浏览器才能访问
httpPost.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36");
//4.判断状态码
List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
parameters.add(new BasicNameValuePair("scope", "project"));
parameters.add(new BasicNameValuePair("q", "java"));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters,"UTF-8");
httpPost.setEntity(formEntity);
//5.发送请求
CloseableHttpResponse response = httpClient.execute(httpPost);
if(response.getStatusLine().getStatusCode()==200){
HttpEntity entity = response.getEntity();
String string = EntityUtils.toString(entity, "utf-8");
System.out.println(string);
}
//6.关闭资源
response.close();
httpClient.close();
}
6.1 创建HttpClient对象的几种方式
HttpClient是一个接口,它的常用实现有AutoRetryHttpClient,CachingHttpClient,DecompressingHttpClient,其中CloseableHttpClient是它的抽象类。
方式一:
使用CloseableHttpClient的工厂类HttpClients的方法来创建实例。
CloseableHttpClient httpClient = HttpClients.createDefault();
方式二:
使用CloseableHttpClient的builder类HttpClientBuilder,先对一些属性进行配置(采用装饰者模式,不断的.setxxxxx().setxxxxxxxx()就行了),再调用build方法来创建实例。
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
6.2 创建request请求
提供的常用请求HttpGet、HttpPost、HttpDelete、HttpPut
// 创建HttpGet请求,相当于在浏览器输入地址
HttpGet httpGet = new HttpGet("http://www.baidu.com/");
6.3 执行Request请求
执行Request请求就是调用HttpClient的execute方法。
CloseableHttpResponse response = httpClient.execute(httpGet);
6.4 处理响应
HttpClient发送请求后的响应其解析后的对象
CloseableHttpClient发送请求后的响应则都是CloseableHttpResponse类型。[用的较多]。
CloseableHttpResponse response = httpClient.execute(httpGet);
//4.判断状态码
if(response.getStatusLine().getStatusCode()==200){
HttpEntity entity = response.getEntity();
//使用工具类EntityUtils,从响应中取出实体表示的内容并转换成字符串
String string = EntityUtils.toString(entity, "utf-8");
System.out.println(string);
}
CloseableHttpResponse常用方法:
自行百度吧
关于其中有个方法 HttpEntity getEntity(); // 获取此响应的消息实体
HttpEntity常用方法:
自行百度吧
6.5 关闭HttpClient
response.close();
httpClient.close();
7. 常见使用案例
https://www.cnblogs.com/licl11092/p/9075677.html
https://www.pianshen.com/article/401974721/
https://blog.csdn.net/justry_deng/article/details/81042379
https://blog.csdn.net/w372426096/article/details/82713315?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.not_use_machine_learn_pai
https://www.cnblogs.com/kitor/p/11235762.html
https://blog.csdn.net/wangpeng047/article/details/19624529
https://blog.csdn.net/zhuwukai/article/details/78644484
https://www.pianshen.com/article/401974721/
8. 其他远程访问接口方式
- java原生API HttpURLConnection 在java.net包中,已经提供访问HTTP协议的基本功能类:HttpURLConnection,可以向其他系统发送GET,POST访问请求 转载
- OKHttp 一种Client/Server模式,可以像调用本地方法一样去调用远程服务器上的方法,它支持多种协议(如:HTTP、TCP、UDP、自定协议)和多种数据传输方式
- RestTemplate 由 Spring 提供的一个 HTTP 请求工具。
- WebService 一种跨编程语言、跨操作系统平台的远程调用技术。 转载
- WebSocket 一种在单个TCP连接上进行全双工通信的协议。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
- ....欢迎评论补充
9. RestTemplate
参考大佬文章:https://blog.csdn.net/jinjiniao1/article/details/100849237
RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及execute。
总结来说就是:RestTemplate字面意思即支持Rest风格架构的互联网的请求方式模板它是一种支持REST风格并简化了发起http请求访问资源以及处理响应的方式。
RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。
相比使用Apache的HttpClient,RestTemplate提供了一种简单便捷的模板类来进行操作。我们只需要传入url及返回值类型即可。
9.1 入门使用
@RestController
public class ServerController {
@GetMapping("/msg")
public String msg(){
return "this is product' msg";
}
}
public static void main(String[] args) {
//请求地址
String url = "http://localhost:8001/msg";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
log.info("response={}",response);
}
RestTemplate定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。
其实,这里面只有11个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了36个方法。
9.2 api解析
a) 创建RestTemplate的三种方式
RestTemplate restTemplate = new RestTemplate();
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
b) 常见的 GET,POST,PUT,DELETE 的用法
//1. 简单Get请求
String result = restTemplate.getForObject(rootUrl + "get1?para=my", String.class);
System.out.println("简单Get请求:" + result);
//2. 简单带路径变量参数Get请求
result = restTemplate.getForObject(rootUrl + "get2/{1}", String.class, 239);
System.out.println("简单带路径变量参数Get请求:" + result);
//3. 返回对象Get请求(注意需包含compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5')
ResponseEntity<Test1> responseEntity = restTemplate.getForEntity(rootUrl + "get3/339", Test1.class);
System.out.println("返回:" + responseEntity);
System.out.println("返回对象Get请求:" + responseEntity.getBody());
//4. 设置header的Get请求
HttpHeaders headers = new HttpHeaders();
headers.add("token", "123");
ResponseEntity<String> response = restTemplate.exchange(rootUrl + "get4", HttpMethod.GET, new HttpEntity<String>(headers), String.class);
System.out.println("设置header的Get请求:" + response.getBody());
//5. Post对象
Test1 test1 = new Test1();
test1.name = "buter";
test1.sex = 1;
result = restTemplate.postForObject(rootUrl + "post1", test1, String.class);
System.out.println("Post对象:" + result);
//6. 带header的Post数据请求
response = restTemplate.postForEntity(rootUrl + "post2", new HttpEntity<Test1>(test1, headers), String.class);
System.out.println("带header的Post数据请求:" + response.getBody());
//7. 带header的Put数据请求
//无返回值
restTemplate.put(rootUrl + "put1", new HttpEntity<Test1>(test1, headers));
//带返回值
response = restTemplate.exchange(rootUrl + "put1", HttpMethod.PUT, new HttpEntity<Test1>(test1, headers), String.class);
System.out.println("带header的Put数据请求:" + response.getBody());
//8. del请求
//无返回值
restTemplate.delete(rootUrl + "del1/{1}", 332);
//带返回值
response = restTemplate.exchange(rootUrl + "del1/332", HttpMethod.DELETE, null, String.class);
System.out.println("del数据请求:" + response.getBody());
c) Get请求解析
看完上面这么多示例,我们来详解一下Get请求。
getForEntity
既然 RestTemplate 发送的是 HTTP 请求,那么在响应的数据中必然也有响应头,如果开发者需要获取响应头的话,那么就需要使用 getForEntity 来发送 HTTP 请求,此时返回的对象是一个 ResponseEntity 的实例。这个实例中包含了响应数据以及响应头。
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, name);
getForEntity 方法。第一个参数是 url ,url 中有一个占位符 {1} ,如果有多个占位符分别用 {2} 、 {3} … 去表示,第二个参数是接口返回的数据类型,最后是一个可变长度的参数,用来给占位符填值。在返回的 ResponseEntity 中,可以获取响应头中的信息,其中 getStatusCode 方法用来获取响应状态码, getBody 方法用来获取响应数据, getHeaders 方法用来获取响应头。
getForObject
getForObject 方法和 getForEntity 方法类似。
getForObject 和 getForEntity 的差异,这两个的差异主要体现在返回值的差异上, getForObject 的返回值就是服务提供者返回的数据,使用 getForObject 无法获取到响应头。
String s = restTemplate.getForObject(uri, String.class);
c) Post请求解析
和 GET 请求相比,RestTemplate 中的 POST 请求多了一个类型的方法。
postForEntity
根据上述描述,可以发现postForEntity可以传递参数为key/value的map形式,json,还能像gey请求那样的传递 key/value 形式的参数。
String url = "http://" + host + ":" + port + "/hello2";
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, map, String.class);
String url = "http://" + host + ":" + port + "/hello2?name={1}";
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, null, String.class,name);
postForEntity之传递 JSON 数据
上面已经说了postForEntity可以传递JSON参数。在 post 请求中,可以自动将一个对象转换成 json 进行传输,数据到达目标接口之后,再被转换为一个对象。
public class User {
private String username;
private String address;
//省略getter/setter
}
@Controller
@ResponseBody
public class UserController {
@PostMapping("/user")
public User hello(@RequestBody User user) {
return user;
}
}
@GetMapping("/hello7")
public User hello7() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/user";
User u1 = new User();
u1.setUsername("牧码小子");
u1.setAddress("深圳");
ResponseEntity<User> responseEntity = restTemplate.postForEntity(url, u1, User.class);
return responseEntity.getBody();
}
postForObject
postForObject 和 postForEntity 基本一致,就是返回类型不同而已,这里不再赘述。
postForLocation
postForLocation 方法的返回值是一个 Uri 对象,因为 POST 请求一般用来添加数据,有的时候需要将刚刚添加成功的数据的 URL 返回来,此时就可以使用这个方法,一个常见的使用场景如用户注册功能,用户注册成功之后,可能就自动跳转到登录页面了,此时就可以使用该方法。
例如在 provider 中提供一个用户注册接口,再提供一个用户登录接口,如下:
@RequestMapping("/register")
public String register(User user) throws UnsupportedEncodingException {
return "redirect:/loginPage?username=" + URLEncoder.encode(user.getUsername(),"UTF-8") + "&address=" + URLEncoder.encode(user.getAddress(),"UTF-8");
}
@GetMapping("/loginPage")
@ResponseBody
public String loginPage(User user) {
return "loginPage:" + user.getUsername() + ":" + user.getAddress();
}
这里一个注册接口,一个是登录页面,不过这里的登录页面我就简单用一个字符串代替了。然后在 consumer 中来调用注册接口,如下:
@GetMapping("/hello8")
public String hello8() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/register";
MultiValueMap map = new LinkedMultiValueMap();
map.add("username", "牧码小子");
map.add("address", "深圳");
URI uri = restTemplate.postForLocation(url, map);
String s = restTemplate.getForObject(uri, String.class);
return s;
}
这里首先调用 postForLocation 获取 Uri 地址,然后再利用 getForObject 请求 Uri,结果如下:
参考大佬文章:https://blog.csdn.net/jinjiniao1/article/details/100849237
注意:postForLocation 方法返回的 Uri 实际上是指响应头的 Location 字段,所以,provider 中 register 接口的响应头必须要有 Location 字段(即请求的接口实际上是一个重定向的接口),否则 postForLocation 方法的返回值为null,初学者很容易犯这个错误,如果这里出错,大家可以参考下我的源代码。