您好,登錄后才能下訂單哦!
前言
作為一個Java后端,需要通過HTTP請求其他的網絡資源可以說是一個比較常見的case了;一般怎么做呢?
可能大部分的小伙伴直接撈起Apache的HttpClient開始做,或者用其他的一些知名的開源庫如OkHttp, 當然原生的HttpURLConnection也是沒問題的
本篇博文則主要關注點放在Sprig的生態下,利用RestTemplate來發起Http請求的使用姿勢
I. RestTempalate 基本使用
0. 目標
在介紹如何使用RestTemplate之前,我們先拋出一些小目標,至少需要知道通過RestTemplate可以做些什么,以及我們要用它來干些什么
簡單的給出了一下常見的問題如下
上面的問題比較多,目測不是一篇博文可以弄完的,因此對這個拆解一下,本篇主要關注在RestTemplate的簡單Get/Post請求的使用方式上
1. 基本接口
撈出源碼,看一下其給出的一些常用接口,基本上可以分為下面幾種
// get 請求 public <T> T getForObject(); public <T> ResponseEntity<T> getForEntity(); // head 請求 public HttpHeaders headForHeaders(); // post 請求 public URI postForLocation(); public <T> T postForObject(); public <T> ResponseEntity<T> postForEntity(); // put 請求 public void put(); // pathch public <T> T patchForObject // delete public void delete() // options public Set<HttpMethod> optionsForAllow // exchange public <T> ResponseEntity<T> exchange()
上面提供的幾個接口,基本上就是Http提供的幾種訪問方式的對應,其中exchange卻又不一樣,后面細說
2. Get請求
從上面的接口命名上,可以看出可以使用的有兩種方式 getForObject 和 getForEntity,那么這兩種有什么區別?
a. 創建Get接口
為了驗證RestTemplate的使用姿勢,當然得先提供一個后端的REST服務,這了直接用了我個人的一個古詩詞的后端接口,來作為簡單的Get測試使用
請求連接: https://story.hhui.top/detail?id=666106231640
返回結果:
{ "status": { "code": 200, "msg": "SUCCESS" }, "result": { "id": 666106231640, "title": "西塞山二首(今謂之道士磯,即興國軍大冶縣", "author": "王周", "content": "西塞名山立翠屏,濃嵐橫入半江青。\n千尋鐵鎖無由問,石壁空存道者形。\n匹婦頑然莫問因,匹夫何去望千春。\n翻思岵屺傳詩什,舉世曾無化石人。", "explain": "", "theme": "無", "dynasty": "唐詩" } }
b. getForObject方式
首先看下完整的接口簽名
@Nullable public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException ; @Nullable public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException ; @Nullable public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException;
有三個重載的方法,從接口上也比較容易看出如何使用,其中有點疑惑的則是第一鐘,參數應該怎么傳了,下面給出上面幾種的使用姿勢
public class RestTestmplateTest { private RestTemplate restTemplate; @Before public void init() { restTemplate = new RestTemplate(); } @lombok.Data static class InnerRes { private Status status; private Data result; } @lombok.Data static class Status { int code; String msg; } @lombok.Data static class Data { long id; String theme; String title; String dynasty; String explain; String content; String author; } @Test public void testGet() { // 使用方法一,不帶參數 String url = "https://story.hhui.top/detail?id=666106231640"; InnerRes res = restTemplate.getForObject(url, InnerRes.class); System.out.println(res); // 使用方法一,傳參替換 url = "https://story.hhui.top/detail?id={?}"; res = restTemplate.getForObject(url, InnerRes.class, "666106231640"); System.out.println(res); // 使用方法二,map傳參 url = "https://story.hhui.top/detail?id={id}"; Map<String, Object> params = new HashMap<>(); params.put("id", 666106231640L); res = restTemplate.getForObject(url, InnerRes.class, params); System.out.println(res); // 使用方法三,URI訪問 URI uri = URI.create("https://story.hhui.top/detail?id=666106231640"); res = restTemplate.getForObject(uri, InnerRes.class); System.out.println(res); } }
看上面的testcase,后面兩個方法的使用沒什么好說的,主要看一下org.springframework.web.client.RestTemplate#getForObject(java.lang.String, java.lang.Class<T>, java.lang.Object...)
的使用姿勢
上面執行后的截圖如下
c. getForEntity方式
既然getForObject有三種使用方法,那么getForEntity理論上也應該有對應的三種方式
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException ; public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;
因為使用姿勢和上面一致,因此只拿一個進行測試
@Test public void testGetForEntity() { String url = "https://story.hhui.top/detail?id=666106231640"; ResponseEntity<InnerRes> res = restTemplate.getForEntity(url, InnerRes.class); System.out.println(res); }
對這個,我們主要關注的就是ResponseEntity封裝中,多了哪些東西,截圖如下
從上面可以看出,多了兩個東西
3. Post請求
從上面的接口說明上看,post請求除了有forObject 和 forEntity之外,還多了個forLocation;其次post與get一個明顯的區別就是傳參的姿勢問題,get的參數一般會待在url上;post的則更常見的是通過表單的方式提交
因此接下來關注的重點在于forLocation是什么,以及如何傳參
a. post接口mock
首先創建一個簡單的提供POST請求的REST服務,基于Spring-boot簡單搭建一個,如下
@ResponseBody @RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST}) public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email, @RequestParam(value = "nick", required = false) String nick) { Map<String, Object> map = new HashMap<>(); map.put("code", "200"); map.put("result", "add " + email + " # " + nick + " success!"); return JSON.toJSONString(map); }
b. postForObject方法
首先看一下接口簽名
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException ; public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType) throws RestClientException ;
上面的三個方法,看起來和前面并沒有太大的區別,只是多了一個request參數,那么具體的使用如何呢?
下面分別給出使用用例
@Test public void testPost() { String url = "http://localhost:8080/post"; String email = "test@hhui.top"; String nick = "一灰灰Blog"; MultiValueMap<String, String> request = new LinkedMultiValueMap<>(); request.add("email", email); request.add("nick", nick); // 使用方法三 URI uri = URI.create(url); String ans = restTemplate.postForObject(uri, request, String.class); System.out.println(ans); // 使用方法一 ans = restTemplate.postForObject(url, request, String.class); System.out.println(ans); // 使用方法一,但是結合表單參數和uri參數的方式,其中uri參數的填充和get請求一致 request.clear(); request.add("email", email); ans = restTemplate.postForObject(url + "?nick={?}", request, String.class, nick); System.out.println(ans); // 使用方法二 Map<String, String> params = new HashMap<>(); params.put("nick", nick); ans = restTemplate.postForObject(url + "?nick={nick}", request, String.class, params); System.out.println(ans); }
復制代碼上面分別給出了三種方法的調用方式,其中post傳參區分為兩種,一個是uri參數即拼接在url中的,還有一個就是表單參數
c. postForEntity
和前面的使用姿勢一樣,無非是多了一層包裝而已,略過不講
d. postForLocation
這個與前面有點區別,從接口定義上來說,主要是
POST 數據到一個URL,返回新創建資源的URL
同樣提供了三個接口,分別如下,需要注意的是返回結果,為URI對象,即網絡資源
public URI postForLocation(String url, @Nullable Object request, Object... uriVariables) throws RestClientException ; public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables) throws RestClientException ; public URI postForLocation(URI url, @Nullable Object request) throws RestClientException ;
那么什么樣的接口適合用這種訪問姿勢呢?
想一下我們一般登錄or注冊都是post請求,而這些操作完成之后呢?大部分都是跳轉到別的頁面去了,這種場景下,就可以使用 postForLocation 了,提交數據,并獲取返回的URI,一個測試如下
首先mock一個后端接口
@ResponseBody @RequestMapping(path = "success") public String loginSuccess(String email, String nick) { return "welcome " + nick; } @RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST}) public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email, @RequestParam(value = "nick", required = false) String nick) { return "redirect:/success?email=" + email + "&nick=" + nick + "&status=success"; }
訪問的測試用例,基本上和前面的一樣,沒有什么特別值得一說的
@Test public void testPostLocation() { String url = "http://localhost:8080/post"; String email = "test@hhui.top"; String nick = "一灰灰Blog"; MultiValueMap<String, String> request = new LinkedMultiValueMap<>(); request.add("email", email); request.add("nick", nick); // 使用方法三 URI uri = restTemplate.postForLocation(url, request); System.out.println(uri); }
執行結果如下
獲取到的就是302跳轉后端url,細心的朋友可能看到上面中文亂碼的問題,如何解決呢?
一個簡單的解決方案就是url編碼一下
@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST}, produces = "charset/utf8") public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email, @RequestParam(value = "nick", required = false) String nick) throws UnsupportedEncodingException { return "redirect:/success?email=" + email + "&nick=" + URLEncoder.encode(nick, "UTF-8") + "&status=success"; }
II. 小結
上面目前只給出了Get/Post兩種請求方式的基本使用方式,并沒有涉及到更高級的如添加請求頭,添加證書,設置代理等,高級的使用篇等待下一篇出爐,下面小結一下上面的使用姿勢
1. Get請求
get請求中,參數一般都是帶在url上,對于參數的填充,有兩種方式,思路一致都是根據實際的參數來填充url中的占位符的內容;根據返回結果,也有兩種方式,一個是只關心返回對象,另一個則包含了返回headers信心
參數填充
1、形如 http://story.hhui.top?id={0} 的 url
2、形如 http://story.hhui.top?id={id} 的 url
其實還有一種傳參方式,就是path參數,填充方式和上面一樣,并沒有什么特殊的玩法,上面沒有特別列出
返回結果
2. Post請求
3. 其他
最前面提了多點關于網絡請求的常見case,但是上面的介紹,明顯只處于基礎篇,我們還需要關注的有
上面可能還停留在應用篇,對于源碼和實現有興趣的話,問題也就來了
小小的一個工具類,其實東西還挺多的,接下來的小目標,就是針對上面提出的點,逐一進行研究
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。