http 協(xié)議
http 協(xié)議是一個(gè)用于傳輸超媒體文檔(例如html)的應(yīng)用層的協(xié)議啄寡。他是為了web瀏覽器和web 服務(wù)器之間的通訊而設(shè)計(jì)的
可以參考:
MDN web Docs
http1.1
現(xiàn)在web中用的最廣的協(xié)議。
HTTP/1.1 主要的功能要點(diǎn):
- 增加了 HEAD彼水、POST 等新方法
- 增加了響應(yīng)狀態(tài)碼,標(biāo)記可能的錯(cuò)誤原因
- 引入了協(xié)議版本號(hào)概念
- 引入了 HTTP Header(頭部)的概念,讓 HTTP 處理請(qǐng)求和響應(yīng)更加靈活
- 傳輸?shù)臄?shù)據(jù)不再僅限于文本
- 增加了 PUT、DELETE 等新的方法续室;
- 增加了緩存管理和控制;
- 明確了連接管理谒养,允許持久連接挺狰;
- 允許響應(yīng)數(shù)據(jù)分塊(chunked)明郭,利于傳輸大文件;
- 強(qiáng)制要求 Host 頭丰泊,讓互聯(lián)網(wǎng)主機(jī)托管成為可能薯定。
等
http2
HTTP/1.1 發(fā)布之后,整個(gè)互聯(lián)網(wǎng)世界呈現(xiàn)出了爆發(fā)式的增長(zhǎng)瞳购,度過(guò)了十多年的“快樂(lè)時(shí)光”话侄,更涌現(xiàn)出了 Facebook、Twitter学赛、淘寶年堆、京東等互聯(lián)網(wǎng)新貴。
這期間也出現(xiàn)了一些對(duì) HTTP 不滿(mǎn)的意見(jiàn)盏浇,主要就是連接慢变丧,無(wú)法跟上迅猛發(fā)展的互聯(lián)網(wǎng),但 HTTP/1.1 標(biāo)準(zhǔn)一直“巋然不動(dòng)”绢掰,無(wú)奈之下人們只好發(fā)明各式各樣的“小花招”來(lái)緩解這些問(wèn)題痒蓬,比如以前常見(jiàn)的切圖、JS 合并等網(wǎng)頁(yè)優(yōu)化手段滴劲。
終于有一天攻晒,搜索巨頭 Google 忍不住了,首先開(kāi)發(fā)了自己的瀏覽器 Chrome班挖,然后推出了新的 SPDY 協(xié)議炎辨,并在 Chrome 里應(yīng)用于自家的服務(wù)器,如同十多年前的網(wǎng)景與微軟一樣聪姿,從實(shí)際的用戶(hù)方來(lái)“倒逼”HTTP 協(xié)議的變革,這也開(kāi)啟了第二次的“瀏覽器大戰(zhàn)”乙嘀。
歷史再次重演末购,不過(guò)這次的勝利者是 Google,Chrome 目前的全球的占有率超過(guò)了 60%虎谢。Google 借此順勢(shì)把 SPDY 推上了標(biāo)準(zhǔn)的寶座盟榴,互聯(lián)網(wǎng)標(biāo)準(zhǔn)化組織以 SPDY 為基礎(chǔ)開(kāi)始制定新版本的 HTTP 協(xié)議,最終在 2015 年發(fā)布了 HTTP/2婴噩,RFC 編號(hào) 7540擎场。
HTTP/2 的制定充分考慮了現(xiàn)今互聯(lián)網(wǎng)的現(xiàn)狀:寬帶、移動(dòng)几莽、不安全迅办,在高度兼容 主要的特點(diǎn)有:
- 二進(jìn)制協(xié)議,不再是純文本
- 可發(fā)起多個(gè)請(qǐng)求章蚣,廢棄了 1.1 里的管道
- 使用專(zhuān)用算法壓縮頭部站欺,減少數(shù)據(jù)傳輸量
- 允許服務(wù)器主動(dòng)向客戶(hù)端推送數(shù)據(jù)
- 增強(qiáng)了安全性,“事實(shí)上”要求加密通信
restTemplate
RestTemplate 是從 Spring3.0 開(kāi)始支持的一個(gè) HTTP 請(qǐng)求工具,它提供了常見(jiàn)的REST請(qǐng)求方案的模版矾策,例如 GET 請(qǐng)求磷账、POST 請(qǐng)求、PUT 請(qǐng)求贾虽、DELETE 請(qǐng)求以及一些通用的請(qǐng)求執(zhí)行方法 exchange 以及 execute逃糟。
- 調(diào)用RestTemplate的默認(rèn)構(gòu)造函數(shù),RestTemplate對(duì)象在底層通過(guò)使用java.net包下的實(shí)現(xiàn)創(chuàng)建HTTP 請(qǐng)求蓬豁,
- 可以通過(guò)使用ClientHttpRequestFactory指定不同的HTTP請(qǐng)求方式绰咽。
ClientHttpRequestFactory接口主要提供了三種實(shí)現(xiàn)方式
1、SimpleClientHttpRequestFactory方式庆尘,此處生成SimpleBufferingClientHttpRequest剃诅,使用HttpURLConnection創(chuàng)建底層的Http請(qǐng)求連接
2、HttpComponentsClientHttpRequestFactory方式驶忌,此處生成HttpComponentsClientHttpRequest矛辕,使用http client來(lái)實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求
3、OkHttp3ClientHttpRequestFactory方式付魔,此處生成OkHttp3ClientHttpRequest聊品,使用okhttp來(lái)實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求
注入 restTemplate
@Configuration
public class RestTemplateConfig {
/**
* 方法1 :無(wú)參數(shù)的默認(rèn)
*
* @return
*/
// @Bean
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
/**
* 方法2 :
* 用 ClientHttpRequestFactory 來(lái)創(chuàng)建http請(qǐng)求
*
* @param requestFactory
* @return
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory) {
return new RestTemplate(requestFactory);
}
/**
* 優(yōu)先用 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 進(jìn)行 get,post 請(qǐng)求
@Resource
private RestTemplate restTemplate;
@GetMapping("/test-restTemplate")
public String testRestTemplate() {
/**
* get 請(qǐng)求
*
* 參數(shù)1 要請(qǐng)求的地址的url 必填項(xiàng)
* 參數(shù)2 響應(yīng)數(shù)據(jù)的類(lèi)型 是String 還是 Map等 必填項(xiàng)
* 參數(shù)3 請(qǐng)求攜帶參數(shù) 選填
*/
restTemplate.getForObject("http://localhost:8802/testRestGet?username=zhangsan", String.class);
/**
* get 請(qǐng)求
*
* 參數(shù)1 要請(qǐng)求的地址的url 必填項(xiàng)
* 參數(shù)2 響應(yīng)數(shù)據(jù)的類(lèi)型 是String 還是 Map等 必填項(xiàng)
* 參數(shù)3 請(qǐng)求攜帶參數(shù) 選填
*/
Map<String, String> uriVariables = new HashMap<>();
uriVariables.put("name", "zhengsan");
restTemplate.getForObject("http://localhost:8802/testRestGet?username={name}", String.class, uriVariables);
/**
* get 請(qǐng)求
*
* getForEntity 方法 得到 返回值類(lèi)型為 ResponseEntity
* 參數(shù)1 要請(qǐng)求的地址的url 必填項(xiàng)
* 參數(shù)2 響應(yīng)數(shù)據(jù)的類(lèi)型 是String 還是 Map等 必填項(xiàng)
* 參數(shù)3 請(qǐng)求攜帶參數(shù) 選填
*/
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8802/testRestGet?username={name}", String.class, uriVariables);
System.out.println("獲取響應(yīng)的狀態(tài):" + responseEntity.getStatusCode());
System.out.println("獲取響應(yīng)的數(shù)據(jù):" + responseEntity.getBody());
/**
* post 請(qǐng)求
*
* 參數(shù)1 要請(qǐng)求的地址的url 必填項(xiàng)
* 參數(shù)2 通過(guò)LinkedMultiValueMap對(duì)象封裝請(qǐng)求參數(shù) 模擬表單參數(shù),封裝在請(qǐng)求體中
* 參數(shù)3 響應(yīng)數(shù)據(jù)的類(lèi)型 是String 還是 Map等 必填項(xiàng)
* 參數(shù)4 請(qǐng)求攜帶參數(shù) 選填
*/
LinkedMultiValueMap<String, String> request = new LinkedMultiValueMap<>();
request.set("username", "zhangsan");
restTemplate.postForObject("http://localhost:8002/testRestPost", request, Map.class);
/**
* post 請(qǐng)求
*
* 參數(shù)1 要請(qǐng)求的地址的url 必填項(xiàng)
* 參數(shù)2 通過(guò)LinkedMultiValueMap對(duì)象封裝請(qǐng)求參數(shù) 模擬表單參數(shù)几苍,封裝在請(qǐng)求體中
* 參數(shù)3 響應(yīng)數(shù)據(jù)的類(lèi)型 是String 還是 Map等 必填項(xiàng)
* 參數(shù)4 請(qǐng)求攜帶參數(shù) 選填
*/
Map<String, String> uriVariables2 = new HashMap<>();
uriVariables.put("address", "china");
restTemplate.postForObject("http://localhost:8802/testRestPost?address={address}", request, Map.class, uriVariables2);
/**
* post 請(qǐng)求
*
* getForEntity 方法 得到 返回值類(lèi)型為 ResponseEntity
* 參數(shù)1 要請(qǐng)求的地址的url 必填項(xiàng)
* 參數(shù)2 通過(guò)LinkedMultiValueMap對(duì)象封裝請(qǐng)求參數(shù) 模擬表單參數(shù)翻屈,封裝在請(qǐng)求體中
* 參數(shù)3 響應(yīng)數(shù)據(jù)的類(lèi)型 是String 還是 Map等 必填項(xiàng)
* 參數(shù)4 請(qǐng)求攜帶參數(shù) 選填
*/
ResponseEntity<String> responseEntity2 = restTemplate.postForEntity("http://localhost:8002/testRestPost", request, String.class, uriVariables2);
System.out.println("獲取響應(yīng)的狀態(tài):" + responseEntity2.getStatusCode());
System.out.println("獲取響應(yīng)的數(shù)據(jù):" + responseEntity2.getBody());
/**
* post 請(qǐng)求
*
* 登錄or注冊(cè)都是post請(qǐng)求,而這些操作完成之后呢妻坝?大部分都是跳轉(zhuǎn)到別的頁(yè)面去了伸眶,這種場(chǎng)景下,就可以使用 postForLocation 了刽宪,提交數(shù)據(jù)厘贼,并獲取返回的URI
* 響應(yīng)參數(shù)要跳轉(zhuǎn)的地址
*/
//uri : "redirect:/success.html"
URI uri = restTemplate.postForLocation("http://localhost:8802/testRestPostLocation", request);
System.out.println("postForLocation請(qǐng)求到的地址為:" + uri);
return null;
}
設(shè)置請(qǐng)求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);
}
}
設(shè)置 Interceptors
restTemplate.setInterceptors(Collections.singletonList(new RestTemplateIntercepor()));
restTemplate.getForObject("http://localhost:8802/testRestGet?username=zhangsan", String.class);
方法2
//1. 設(shè)置請(qǐng)求頭參數(shù)
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. 模擬表單參數(shù) 請(qǐng)求體攜帶參數(shù)
LinkedMultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("username", "zhangsan");
//3. 封裝HttpEntity對(duì)象
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(requestBody, requestHeaders);
//4.獲取 restTemplate
RestTemplate restTemplate2 = new RestTemplate();
//5.請(qǐng)求url
ResponseEntity<String> responseEntity =restTemplate2.postForEntity("http://localhost:8802/testRestPost",requestEntity,String.class);
System.out.println("獲取響應(yīng)的狀態(tài):" + responseEntity.getStatusCode());
System.out.println("獲取響應(yīng)的數(shù)據(jù):" + responseEntity.getBody());
http 協(xié)議參考文檔:
http2協(xié)議(英文)
w3cschool介紹
restTemplate參考:
HttpClient、RestTemplate和Feign相關(guān)知識(shí)
使用RestTemplate和Feign進(jìn)行微服務(wù)通信
restTemplate使用指南
基于springboot的RestTemplate圣拄、okhttp和HttpClient對(duì)比