http 协议
http 协议是一个用于传输超媒体文档(例如html)的应用层的协议。他是为了web浏览器和web 服务器之间的通讯而设计的
可以参考:
MDN web Docs
http1.1
现在web中用的最广的协议。
HTTP/1.1 主要的功能要点:
- 增加了 HEAD、POST 等新方法
- 增加了响应状态码,标记可能的错误原因
- 引入了协议版本号概念
- 引入了 HTTP Header(头部)的概念,让 HTTP 处理请求和响应更加灵活
- 传输的数据不再仅限于文本
- 增加了 PUT、DELETE 等新的方法;
- 增加了缓存管理和控制;
- 明确了连接管理,允许持久连接;
- 允许响应数据分块(chunked),利于传输大文件;
- 强制要求 Host 头,让互联网主机托管成为可能。
等
http2
HTTP/1.1 发布之后,整个互联网世界呈现出了爆发式的增长,度过了十多年的“快乐时光”,更涌现出了 Facebook、Twitter、淘宝、京东等互联网新贵。
这期间也出现了一些对 HTTP 不满的意见,主要就是连接慢,无法跟上迅猛发展的互联网,但 HTTP/1.1 标准一直“岿然不动”,无奈之下人们只好发明各式各样的“小花招”来缓解这些问题,比如以前常见的切图、JS 合并等网页优化手段。
终于有一天,搜索巨头 Google 忍不住了,首先开发了自己的浏览器 Chrome,然后推出了新的 SPDY 协议,并在 Chrome 里应用于自家的服务器,如同十多年前的网景与微软一样,从实际的用户方来“倒逼”HTTP 协议的变革,这也开启了第二次的“浏览器大战”。
历史再次重演,不过这次的胜利者是 Google,Chrome 目前的全球的占有率超过了 60%。Google 借此顺势把 SPDY 推上了标准的宝座,互联网标准化组织以 SPDY 为基础开始制定新版本的 HTTP 协议,最终在 2015 年发布了 HTTP/2,RFC 编号 7540。
HTTP/2 的制定充分考虑了现今互联网的现状:宽带、移动、不安全,在高度兼容 主要的特点有:
- 二进制协议,不再是纯文本
- 可发起多个请求,废弃了 1.1 里的管道
- 使用专用算法压缩头部,减少数据传输量
- 允许服务器主动向客户端推送数据
- 增强了安全性,“事实上”要求加密通信
restTemplate
RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。
- 调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,
- 可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
ClientHttpRequestFactory接口主要提供了三种实现方式
1、SimpleClientHttpRequestFactory方式,此处生成SimpleBufferingClientHttpRequest,使用HttpURLConnection创建底层的Http请求连接
2、HttpComponentsClientHttpRequestFactory方式,此处生成HttpComponentsClientHttpRequest,使用http client来实现网络请求
3、OkHttp3ClientHttpRequestFactory方式,此处生成OkHttp3ClientHttpRequest,使用okhttp来实现网络请求
注入 restTemplate
@Configuration
public class RestTemplateConfig {
/**
* 方法1 :无参数的默认
*
* @return
*/
// @Bean
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
/**
* 方法2 :
* 用 ClientHttpRequestFactory 来创建http请求
*
* @param requestFactory
* @return
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory) {
return new RestTemplate(requestFactory);
}
/**
* 优先用 SimpleClientHttpRequestFactory
* @return
*/
@Primary
@Bean
public ClientHttpRequestFactory simpleClient() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
//单位为ms
factory.setReadTimeout(5000);
//单位为ms
factory.setConnectTimeout(5000);
return factory;
}
@Bean
public ClientHttpRequestFactory okhttpClient() {
OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory();
//单位为ms
factory.setReadTimeout(5000);
//单位为ms
factory.setConnectTimeout(5000);
return factory;
}
}
使用 restTemplate 进行 get,post 请求
@Resource
private RestTemplate restTemplate;
@GetMapping("/test-restTemplate")
public String testRestTemplate() {
/**
* get 请求
*
* 参数1 要请求的地址的url 必填项
* 参数2 响应数据的类型 是String 还是 Map等 必填项
* 参数3 请求携带参数 选填
*/
restTemplate.getForObject("http://localhost:8802/testRestGet?username=zhangsan", String.class);
/**
* get 请求
*
* 参数1 要请求的地址的url 必填项
* 参数2 响应数据的类型 是String 还是 Map等 必填项
* 参数3 请求携带参数 选填
*/
Map<String, String> uriVariables = new HashMap<>();
uriVariables.put("name", "zhengsan");
restTemplate.getForObject("http://localhost:8802/testRestGet?username={name}", String.class, uriVariables);
/**
* get 请求
*
* getForEntity 方法 得到 返回值类型为 ResponseEntity
* 参数1 要请求的地址的url 必填项
* 参数2 响应数据的类型 是String 还是 Map等 必填项
* 参数3 请求携带参数 选填
*/
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8802/testRestGet?username={name}", String.class, uriVariables);
System.out.println("获取响应的状态:" + responseEntity.getStatusCode());
System.out.println("获取响应的数据:" + responseEntity.getBody());
/**
* post 请求
*
* 参数1 要请求的地址的url 必填项
* 参数2 通过LinkedMultiValueMap对象封装请求参数 模拟表单参数,封装在请求体中
* 参数3 响应数据的类型 是String 还是 Map等 必填项
* 参数4 请求携带参数 选填
*/
LinkedMultiValueMap<String, String> request = new LinkedMultiValueMap<>();
request.set("username", "zhangsan");
restTemplate.postForObject("http://localhost:8002/testRestPost", request, Map.class);
/**
* post 请求
*
* 参数1 要请求的地址的url 必填项
* 参数2 通过LinkedMultiValueMap对象封装请求参数 模拟表单参数,封装在请求体中
* 参数3 响应数据的类型 是String 还是 Map等 必填项
* 参数4 请求携带参数 选填
*/
Map<String, String> uriVariables2 = new HashMap<>();
uriVariables.put("address", "china");
restTemplate.postForObject("http://localhost:8802/testRestPost?address={address}", request, Map.class, uriVariables2);
/**
* post 请求
*
* getForEntity 方法 得到 返回值类型为 ResponseEntity
* 参数1 要请求的地址的url 必填项
* 参数2 通过LinkedMultiValueMap对象封装请求参数 模拟表单参数,封装在请求体中
* 参数3 响应数据的类型 是String 还是 Map等 必填项
* 参数4 请求携带参数 选填
*/
ResponseEntity<String> responseEntity2 = restTemplate.postForEntity("http://localhost:8002/testRestPost", request, String.class, uriVariables2);
System.out.println("获取响应的状态:" + responseEntity2.getStatusCode());
System.out.println("获取响应的数据:" + responseEntity2.getBody());
/**
* post 请求
*
* 登录or注册都是post请求,而这些操作完成之后呢?大部分都是跳转到别的页面去了,这种场景下,就可以使用 postForLocation 了,提交数据,并获取返回的URI
* 响应参数要跳转的地址
*/
//uri : "redirect:/success.html"
URI uri = restTemplate.postForLocation("http://localhost:8802/testRestPostLocation", request);
System.out.println("postForLocation请求到的地址为:" + uri);
return null;
}
设置请求header
方法1 先配置http的request拦截器
public class RestTemplateIntercepor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = httpRequest.getHeaders();
headers.add(HttpHeaders.USER_AGENT,
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36");
//add自己的header
return execution.execute(httpRequest, body);
}
}
设置 Interceptors
restTemplate.setInterceptors(Collections.singletonList(new RestTemplateIntercepor()));
restTemplate.getForObject("http://localhost:8802/testRestGet?username=zhangsan", String.class);
方法2
//1. 设置请求头参数
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add(HttpHeaders.USER_AGENT,
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36");
//2. 模拟表单参数 请求体携带参数
LinkedMultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("username", "zhangsan");
//3. 封装HttpEntity对象
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(requestBody, requestHeaders);
//4.获取 restTemplate
RestTemplate restTemplate2 = new RestTemplate();
//5.请求url
ResponseEntity<String> responseEntity =restTemplate2.postForEntity("http://localhost:8802/testRestPost",requestEntity,String.class);
System.out.println("获取响应的状态:" + responseEntity.getStatusCode());
System.out.println("获取响应的数据:" + responseEntity.getBody());
http 协议参考文档:
http2协议(英文)
w3cschool介绍
restTemplate参考:
HttpClient、RestTemplate和Feign相关知识
使用RestTemplate和Feign进行微服务通信
restTemplate使用指南
基于springboot的RestTemplate、okhttp和HttpClient对比