日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Http请求之优雅的RestTemplate

發布時間:2023/11/28 生活经验 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Http请求之优雅的RestTemplate 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

本篇博客為對RestTemplate總結

HttpURLConnection

在講RestTemplate之前我們來看看再沒有RestTemplate之前是怎么發送http請求的。

private String httpRequest(String api){BufferedReader in = null;StringBuffer result;try {URL url = new URL(api);//打開和url之間的連接HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");connection.setRequestProperty("Charset", "utf-8");connection.connect();result = new StringBuffer();//讀取URL的響應in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String line;while ((line = in.readLine()) != null) {result.append(line);}return result.toString(); //返回json字符串} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}}return null;}

可以看到需要使用HttpURLConnection去打開連接,然后再設置一堆請求參數,通過流讀取URL的響應結果后還要遍歷流封裝數據,最后還要關閉連接,可謂非常繁瑣。如果使用RestTemplate發送同樣的一個請求的話,只需要一步:

String str = restTemplate.getForObject(api,String.class);

跟進RestTemplate源碼,可以看到RestTemplate底層就是對HttpURLConnection的封裝,幫我們解決了那些繁瑣的過程

@Overridepublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);prepareConnection(connection, httpMethod.name());if (this.bufferRequestBody) {return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);}else {return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);}}

RestTemplate簡介

RestTemplate 是從 Spring3.0 開始支持的一個 HTTP 請求工具,它提供了常見的REST請求方案的模版,例如 GET 請求、POST 請求、PUT 請求、DELETE 請求以及一些通用的請求執行方法 exchange 以及 execute。RestTemplate 繼承自 InterceptingHttpAccessor 并且實現了 RestOperations 接口,其中 RestOperations 接口定義了基本的 RESTful 操作,這些操作在 RestTemplate 中都得到了實現。說白了RestTemplate就是Spring提供的一個訪問Http服務的客戶端類,在微服務之間的調用,接口調用就需要使用的RestTemplate

Get請求


可以看到,使用RestTemplate發送get請求主要有兩類方法,分別是getForEntity和getForObject,兩類方法又分別有三個重載方法,接下來我們看看這兩個方法。

getForEntity

getForEntity返回類型是ResponseEntity,也就是說如果開發者需要獲取響應頭的話,那么就需要使用 getForEntity 來發送 HTTP 請求,此時返回的對象是一個 ResponseEntity 的實例。這個實例中包含了響應數據以及響應頭。看下它的三個重載方法:

@Overridepublic <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));}@Overridepublic <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));}@Overridepublic <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor));}

可以看到有兩個必填的參數,第一個參數是請求接口的url,第二個參數是響應結果中響應體的類型。第三是選填的參數,http請求攜帶的參數,有兩種類型,一種是以map的形式,另一種則為占位符的格式,類似于sql中的占位符。

  private JSONObject sendGetRequest(Map<String,Object> map){ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map); return JSONObject.parseObject(json);}
 String url = "http://" + host + ":" + port + "/sayHello?name={1}&sex={2}";ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, name,sex); 

當然我們也可以直接在url后面拼接參數。

  private JSONObject sendGetRequest(Map<String,Object> map){StringBuilder accessRequestUrl = new StringBuilder(cspProperties.getUrl() + "?");Set<String> keys = map.keySet();List<String> list = new ArrayList<>(keys);for (String key : list) {accessRequestUrl.append(key).append("=").append(map.get(key).toString()).append("&");}accessRequestUrl.subSequence(0,accessRequestUrl.length() - 1);ResponseEntity<String> json = restTemplate.getForEntity(accessRequestUrl.toString(),String.class);return JSONObject.parseObject(json);}

getForObject

getForObject和getForEntity類似,唯一的區別就是getForObject返回參數就是接口返回的數據,它不會返回響應頭等信息。如果只關心數據本身而不關心響應頭等信息就可以使用該方法。

@Override@Nullablepublic <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);HttpMessageConverterExtractor<T> responseExtractor =new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);}@Override@Nullablepublic <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);HttpMessageConverterExtractor<T> responseExtractor =new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);}@Override@Nullablepublic <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);HttpMessageConverterExtractor<T> responseExtractor =new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);return execute(url, HttpMethod.GET, requestCallback, responseExtractor);}

POST 請求


post 請求的方法類型除了 postForEntity 和 postForObject 之外,還有一個 postForLocation。這里的方法類型雖然有三種,但是這三種方法重載的參數基本是一樣的。

postForEntity

@Overridepublic <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,Class<T> responseType, Object... uriVariables) throws RestClientException {RequestCallback requestCallback = httpEntityCallback(request, responseType);ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));}@Overridepublic <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {RequestCallback requestCallback = httpEntityCallback(request, responseType);ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));}@Overridepublic <T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType)throws RestClientException {RequestCallback requestCallback = httpEntityCallback(request, responseType);ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor));}

post中的postForEntity和postForObject返回類型和get方法一樣,這里就不敘述,我們來看看參數。其它參數沒啥好說的,上面都提到了,可以看出出現了一個新的參數 Object request,這個是什么?跟進源碼:

public HttpEntityRequestCallback(@Nullable Object requestBody, @Nullable Type responseType) {super(responseType); // requestBody 就是 request參數if (requestBody instanceof HttpEntity) {this.requestEntity = (HttpEntity<?>) requestBody;}else if (requestBody != null) {this.requestEntity = new HttpEntity<>(requestBody);}else {this.requestEntity = HttpEntity.EMPTY;}}

可以看到,request是一個HttpEntity類型,HttpEntity其實相當于一個消息實體,內容是http傳送的報文(主要是json文件)。這里只需要知道它是用來表征一個http報文的實體就行了,用來發送或接收。舉個例子:

 private JSONObject sendPostRequest(Map<String,String> map){HttpHeaders headers = new HttpHeaders();headers.set("Content-Type","application/json;charset=UTF-8");headers.set("Accept","application/json");headers.set("Accept-Encoding","");String url = osyProperties.getUrl();Map<String,Object> requestMessage = new HashMap<>();// 請求報文頭參數Map<String, Object> head = getRequestHeadersParams();requestMessage.put("head",head);// 請求報文體參數HashMap<String, Map<String,String>> body = new HashMap<>();requestMessage.put("body",map);HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestMessage, headers);ResponseEntity<String> entity = restTemplate.postForEntity(url, request, String.class);System.out.println(entity);String body = entity.getBody();return JSONObject.parseObject(body);}

上面代碼發送的報文形式如下(json格式,接口的參數應對應也是json接受,即參數前加上 @RequestBody注解):

{"head": {報文頭參數:值},"body": {報文體參數:值}},
}

HttpEntity實例化的源碼

public HttpEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers) {this.body = body;HttpHeaders tempHeaders = new HttpHeaders();if (headers != null) {tempHeaders.putAll(headers);}this.headers = HttpHeaders.readOnlyHttpHeaders(tempHeaders);}

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 "username:" + user.getUsername();
}

這里一個注冊接口,一個是登錄頁面,不過這里的登錄頁面我就簡單用一個字符串代替了。然后在 consumer 中來調用注冊接口,如下:

@GetMapping("/hello")
public String sayHello() {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", "dave");URI uri = restTemplate.postForLocation(url, map);String s = restTemplate.getForObject(uri, String.class);return s;
}

這里首先調用 postForLocation 獲取 Uri 地址,然后再利用 getForObject 請求 Uri,界面結果為:username:dave。
注意:postForLocation 方法返回的 Uri 實際上是指響應頭的 Location 字段,所以,provider 中 register 接口的響應頭必須要有 Location 字段(即請求的接口實際上是一個重定向的接口),否則 postForLocation 方法的返回值為null。

總結

以上是生活随笔為你收集整理的Http请求之优雅的RestTemplate的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。