resttemplate get請求_簡單粗暴的RestTemplate
阿新 • • 發佈:2020-12-18
技術標籤:resttemplate get請求resttemplate get請求引數resttemplate get請求設定headerresttemplate post提交jsonresttemplate post請求resttemplate post請求json引數求
前言通常訪問http介面,我們有時候會使用httpclient,但是其程式碼複雜,還得費心進行各種資源回收的編寫,不建議直接使用。而RestTemplate是Spring提供的用於訪問Rest服務的客戶端,對get,post等請求以及反序列化支援都封裝的比較好,使用起來簡單粗暴優雅。但是筆者在使用時候碰到一些問題:1、亂碼。2、不同的請求需要設定不同的超時時間。 故整理出來與大家分享如何循序漸進的封裝一個比較使用順手、完善的配置類。 一、RestTemplate初步配置import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
/**
* RestTemplate配置類
*/
@Configuration
publicclassRestTemplateConfig{
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);//讀超時 單位為ms
factory.setConnectTimeout(5000);//連線超時 單位為ms
return factory;
}
}
基於上面這點微量的配置程式碼,我們我們已經可以進行編寫http請求程式碼了,粗暴簡單吧!
二、使用初探import lombok.Data;
import java.io.Serializable;
@Data
public class PersonRequest implements Serializable {
// 請求引數
}
import lombok.Data;
import java.io.Serializable;
@Data
public class Person implements Serializable {
/**名稱*/
private String name;
/**年齡*/
private int age;
}
public static void main(String[] args){
PersonRequest request= new PersonRequest ()
Person person= restTemplate.postForObject("http://172.27.249.130:3000/entity_service",
JSONObject.toJSONString(request),Person.class);
}
三、問題亂碼配置如果只是上述簡單配置,那麼我們在服務端接受到的引數會出現中文亂碼
{\"name\":\"??\",\"age\":18},這是因為我這裡是以String格式提交資料的,底層其實採用的是StringHttpMessageConverter來處理請求,預設是ISO-8859-1字符集
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 解決字串編碼預設iso亂碼問題,將字符集強制設定為UTF-8
List>> list = restTemplate.getMessageConverters();
for (HttpMessageConverter> httpMessageConverter : list) {
if (httpMessageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(StandardCharsets.UTF_8);
break;
}
}
return restTemplate;
}
這個時候我們的亂碼就解決了
{\"name\":\"一斛墨水\",\"age\":18}
四、超時問題
我們的初步配置中,超時時間寫死了,那麼對於我們的url介面,可能A介面處理的慢,10秒鐘才能返回,B介面1分鐘才能返回,而C介面10毫秒就返回了,預設配置超時時間肯定不行,A和B介面只會觸發超時。那有沒有什麼辦法能夠針對不同的介面設定不同的超時時間呢?
// 通過原始碼跟蹤我們發現,
// org.apache.http.impl.execchain.MainClientExec#execute
// 在發起請求時會優先使用HttpClientContext中的超時時間設定
@Override
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
....
final int timeout = config.getSocketTimeout();
if (timeout >= 0) {
managedConn.setSocketTimeout(timeout);
}
....
}
//而config.getSocketTimeout()取的是RequestConfig屬性socketTimeout的值
// 那麼我們就需要再使用的時候,每次重新設定這個值就可以了
五、超時配置
import org.apache.http.client.HttpClient;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.protocol.HttpClientContext;import org.apache.http.protocol.HttpContext;import org.springframework.http.HttpMethod;import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;import java.net.URI;// 參考了https://blog.csdn.net/baozhutang/article/details/88664333public class RestmelateFactory extends HttpComponentsClientHttpRequestFactory { // 每次請求都可以設定超時時間 單位毫秒 the timeout value in milliseconds public static ThreadLocal socketTimeoutThreadLocal = new ThreadLocal<>(); public RestmelateFactory(HttpClient httpClient) { super(httpClient); } @Override protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { HttpContext context = HttpClientContext.create(); RequestConfig config = createRequestConfig(getHttpClient());//每次都從新設定超時時間 // 從ThreadLocal中獲取超時時間,並設定到context中 Integer socketTimeout = socketTimeoutThreadLocal.get(); if (null != socketTimeout) { RequestConfig.Builder builder = RequestConfig.copy(config); builder.setSocketTimeout(socketTimeout); config = builder.build(); } context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); return context; }}@Beanpublic ClientHttpRequestFactory restTemplateFactory() { HttpClientBuilder httpClientBuilder = HttpClients.custom();//HttpClient相關配置 RestTemplateFactory factory = new RestTemplateFactory(httpClient); factory.setConnectTimeout(5000); // 即為 SocketTimeout factory.setReadTimeout(30000); factory.setConnectionRequestTimeout(5000); return factory;}// 這次在使用,就可以根據不同的請求設定不同的超時時間了// 可以再url服務端打上斷點,一直等到restTemplate超時,// 會發現日誌前後呼叫耗時就是你得超時時間public static void main(String[] args) { try { // 設定當前請求超時時間 RestTemplateFactory.socketTimeoutThreadLocal.set(10); PersonRequest request = new PersonRequest() log.info("handler, start request:" + request); try { Person person = restTemplate.postForObject("http://172.27.249.130:3000/entity_service", JSONObject.toJSONString(request), Person.class); } catch (RestClientException e) { log.error("handler介面異常, request:" + request, e); } } finally { // 清理ThreadLocal中超時時間 RestTemplateFactory.socketTimeoutThreadLocal.remove(); }}
六、切面設定超時時間每次呼叫都要編寫重複程式碼設定超時時間到ThreadLocal,我強迫症,不能忍。大家要是能忍的話就可以不用再往下看了。下面我們就使用註解加切面消除這項重複工作。
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * RestTemplate配置,比如目前只有的超時 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface RestTemplateAnnotation { /**請求超時 the timeout value in milliseconds*/ int timeout();}import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@[email protected]@Slf4jpublic class RestTemplateAspect {@Pointcut(value="@annotation(com.annotation.RestTemplateAnnotation)") public void accessOperation() { } @Around(value = "accessOperation() && @annotation(restTemplateAnnotation)") public Object doAround(ProceedingJoinPoint joinPoint, RestTemplateAnnotation restTemplateAnnotation) throws Throwable { try { // 設定當前請求超時時間 HttpClientRequestFactory.socketTimeoutThreadLocal.set(restTemplateAnnotation.timeout()); return joinPoint.proceed(); } finally { // 清理ThreadLocal中超時時間 HttpClientRequestFactory.socketTimeoutThreadLocal.remove(); } }}/***註解使用**@paramrequest*@return*/@RestTemplateAnnotation(timeout=60000)public void handler () { PersonRequest request = new PersonRequest() log.info("handler, start request:" + request); try { Person person = restTemplate.postForObject("http://172.27.249.130:3000/entity_service", JSONObject.toJSONString(request), Person.class); } catch (RestClientException e) { log.error("handler介面異常, request:" + request, e); }}
至此我們就完成了一個使用簡單粗暴優雅的http呼叫封裝
五、預告
下期 :讓電腦桌面煩人的羞羞廣告彈窗無處遁形如果此文對您有所幫助,煩請關注一下,以方便之後的文章能更及時、更好的幫助到您,謝謝!