Http
請求在服務端開發中必不可少,本文使用RestTemplate
作門面,HttpClient
作實現,演示基礎的Http
請求例子。html
pom.xml
依賴RestTemplate
在Spring-Web
模塊中內置,SpringBoot
自動引入<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.5</version> </dependency> <!-- 若是不配異步(AsyncRestTemplate),則不須要這個依賴 --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.5.Final</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
application.yml
(可選)# yml配置的優先級高於java配置;若是yml配置和java配置同時存在,則yml配置會覆蓋java配置 ####restTemplate的yml配置開始#### --- spring: restTemplate: maxTotalConnect: 1000 #鏈接池的最大鏈接數,0表明不限;若是取0,須要考慮鏈接泄露致使系統崩潰的後果 maxConnectPerRoute: 200 connectTimeout: 3000 readTimeout: 5000 charset: UTF-8 ####restTemplate的 yml配置開始####
RestTemplate
配置(必備)// 必備 @Configuration @ConfigurationProperties(prefix = "spring.restTemplate") @ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class}) public class RestTemplateConfig { // java配置的優先級低於yml配置;若是yml配置不存在,會採用java配置 // ####restTemplate的 java配置開始#### private int maxTotalConnection = 500; //鏈接池的最大鏈接數 private int maxConnectionPerRoute = 100; //同路由的併發數 private int connectionTimeout = 2 * 1000; //鏈接超時,默認2s private int readTimeout = 30 * 1000; //讀取超時,默認30s private String charset = "UTF-8"; public void setMaxTotalConnection(int maxTotalConnection) { this.maxTotalConnection = maxTotalConnection; } public void setMaxConnectionPerRoute(int maxConnectionPerRoute) { this.maxConnectionPerRoute = maxConnectionPerRoute; } public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } public void setReadTimeout(int readTimeout) { this.readTimeout = readTimeout; } public void setCharset(String charset) { this.charset = charset; } //建立HTTP客戶端工廠 @Bean(name = "clientHttpRequestFactory") public ClientHttpRequestFactory clientHttpRequestFactory() { return createClientHttpRequestFactory(this.connectionTimeout, this.readTimeout); } //初始化RestTemplate,並加入spring的Bean工廠,由spring統一管理 @Bean(name = "restTemplate") @ConditionalOnMissingBean(RestTemplate.class) public RestTemplate restTemplate(ClientHttpRequestFactory factory) { return createRestTemplate(factory); } //初始化支持異步的RestTemplate,並加入spring的Bean工廠,由spring統一管理 //若是你用不到異步,則無須建立該對象 @Bean(name = "asyncRestTemplate") @ConditionalOnMissingBean(AsyncRestTemplate.class) public AsyncRestTemplate asyncRestTemplate(RestTemplate restTemplate) { final Netty4ClientHttpRequestFactory factory = new Netty4ClientHttpRequestFactory(); factory.setConnectTimeout(this.connectionTimeout); factory.setReadTimeout(this.readTimeout); return new AsyncRestTemplate(factory, restTemplate); } private ClientHttpRequestFactory createClientHttpRequestFactory(int connectionTimeout, int readTimeout) { //maxTotalConnection 和 maxConnectionPerRoute 必需要配 if (this.maxTotalConnection <= 0) { throw new IllegalArgumentException("invalid maxTotalConnection: " + maxTotalConnection); } if (this.maxConnectionPerRoute <= 0) { throw new IllegalArgumentException("invalid maxConnectionPerRoute: " + maxTotalConnection); } //全局默認的header頭配置 List<Header> headers = new LinkedList<>(); headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate")); headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6")); //禁用自動重試,須要重試時,請自行控制 HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(0, false); //建立真正處理http請求的httpClient實例 CloseableHttpClient httpClient = HttpClients.custom() .setDefaultHeaders(headers) .setRetryHandler(retryHandler) .build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory( httpClient); factory.setConnectTimeout(connectionTimeout); factory.setReadTimeout(readTimeout); return factory; } private RestTemplate createRestTemplate(ClientHttpRequestFactory factory) { RestTemplate restTemplate = new RestTemplate(factory); //咱們採用RestTemplate內部的MessageConverter //從新設置StringHttpMessageConverter字符集,解決中文亂碼問題 modifyDefaultCharset(restTemplate); //設置錯誤處理器 restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); return restTemplate; } private void modifyDefaultCharset(RestTemplate restTemplate) { List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters(); HttpMessageConverter<?> converterTarget = null; for (HttpMessageConverter<?> item : converterList) { if (StringHttpMessageConverter.class == item.getClass()) { converterTarget = item; break; } } if (null != converterTarget) { converterList.remove(converterTarget); } Charset defaultCharset = Charset.forName(charset); converterList.add(1, new StringHttpMessageConverter(defaultCharset)); } }
RestTemplate
實例Get
請求演示@Slf4j @RestController public class GetTestController { @Resource private RestTemplate restTemplate; //最簡單的get操做 @GetMapping("/baidu1/{key}") public String get1(@PathVariable String key) throws UnsupportedEncodingException { String encodeKey = URLEncoder.encode(key, "UTF-8"); String url = "http://www.baidu.com/s?bdorz_come=1&ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=" + encodeKey; return restTemplate.getForObject(url, String.class); //返回百度主站html } //須要自定義header頭的get操做 @GetMapping("/baidu2/{key}") public String get2(@PathVariable String key) throws UnsupportedEncodingException { HttpHeaders headers = new HttpHeaders(); headers.set("MyHeaderKey", "MyHeaderValue"); HttpEntity entity = new HttpEntity(headers); String encodeKey =URLEncoder.encode(key, "UTF-8"); String url = "http://www.baidu.com/s?bdorz_come=1&ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=" + encodeKey; ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); return response.getBody(); //返回百度主站html } }
Post
請求演示@Slf4j @RestController public class PostTestController { @Resource private RestTemplate restTemplate; //post表單演示 @GetMapping("/postForm") public String testPostForm() { // 填寫url String url = ""; MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>(); // 填寫表單 form.add("name", "**"); form.add("age", "**"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); //headers.add("xx", "yy");//能夠加入自定義的header頭 HttpEntity<MultiValueMap<String, String>> formEntity = new HttpEntity<>(form, headers); String json = restTemplate.postForObject(url, formEntity, String.class); return json; } @RequestMapping("/postBody") public String testPostBody() { // 填寫url String url = ""; // 填寫json串 String jsonBody = "{\n" + " \"name\": \"XX\",\n" + " \"age\": \"12\",\n" + " \"sex\": \"man\"\n" + "}\n"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); //headers.add("xx", "yy");//能夠加入自定義的header頭 HttpEntity<String> bodyEntity = new HttpEntity<>(jsonBody, headers); //1.直接拿原始json串 String json = restTemplate.postForObject(url, bodyEntity, String.class); //2.將原始的json傳轉成java對象,rest template能夠自動完成 ResultVo resultVo = restTemplate.postForObject(url, bodyEntity, ResultVo.class); if (resultVo != null && resultVo.success()) { Object res = resultVo.getData(); log.info("處理成功,返回數據: {}", resultVo.getData()); } else { log.info("處理失敗,響應結果: {}", resultVo); } return json;//返回的是分包api的json } }
@Slf4j @RestController public class FileTestController { @Resource private RestTemplate restTemplate; // post文件上傳 // 場景說明:只適合小文件(20MB之內)上傳 @RequestMapping("/postFile") public String testPostFileBody() { String filePath = "D:/config.png"; //經過磁盤文件上傳,若是產生了臨時文件,必定要記得刪除,不然,臨時文件越積越多,磁盤會爆 FileSystemResource resource = new FileSystemResource(new File(filePath)); String url = "***";//測試的時候換成本身的配置 String appId = "***";//測試的時候換成本身的配置 String secureKey = "***";//測試的時候換成本身的配置 String time = String.valueOf(System.currentTimeMillis()); String pubStr = "1"; String tempStr = String.format("app_id=%s&is_public=%s&time=%s&vframe=0%s", appId, pubStr, time, secureKey); MultiValueMap<String, Object> form = new LinkedMultiValueMap<>(); form.add("is_public", pubStr); form.add("vframe", "0"); form.add("file", resource); form.add("app_id", appId); form.add("time", time); form.add("sign", DigestUtils.md5(tempStr)); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); //headers.add("xx", "yy");//能夠加入自定義的header頭 HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<>(form, headers); String json = restTemplate.postForObject(url, formEntity, String.class); return json; } //文件下載 //場景說明:只適合小文件(10MB之內)下載 @RequestMapping("/downloadFile") public ResponseEntity testDownloadFile() throws Exception { String url = "http://editor.baidu.com/editor/download/BaiduEditor(Online)_5-9-16.exe"; HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM)); HttpEntity<String> entity = new HttpEntity<>(headers); ResponseEntity<byte[]> response = restTemplate.exchange(url, HttpMethod.GET, entity, byte[].class); byte[] bytes = response.getBody(); long contentLength = bytes != null ? bytes.length : 0; headers.setContentLength((int) contentLength); headers.setContentDispositionFormData("baidu.exe", URLEncoder.encode("百度安裝包.exe", "UTF-8")); return new ResponseEntity<>(response.getBody(), headers, HttpStatus.OK); } }
@ConfigurationProperties
時,不會自動建立bean
正確姿式:java
@Configuration @ConfigurationProperties(prefix = "spring.restTemplate") @ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class}) public class RestTemplateConfig { }
錯誤姿式:git
@ConfigurationProperties(prefix = "spring.restTemplate") @ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class}) public class RestTemplateConfig { }
@ConfigurationProperties
沒法注入沒有setter
的屬性RestTemplate
默認配置會亂碼正確姿式:github
private RestTemplate createRestTemplate(ClientHttpRequestFactory factory) { RestTemplate restTemplate = new RestTemplate(factory); //咱們採用RestTemplate內部的MessageConverter //從新設置StringHttpMessageConverter字符集,解決中文亂碼問題 modifyDefaultCharset(restTemplate); //設置錯誤處理器 restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); return restTemplate; } private void modifyDefaultCharset(RestTemplate restTemplate) { List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters(); HttpMessageConverter<?> converterTarget = null; for (HttpMessageConverter<?> item : converterList) { if (StringHttpMessageConverter.class == item.getClass()) { converterTarget = item; break; } } if (null != converterTarget) { converterList.remove(converterTarget); } Charset defaultCharset = Charset.forName(charset); converterList.add(1, new StringHttpMessageConverter(defaultCharset)); }
錯誤姿式:spring
@Bean public RestTemplate getRestTemplate(){ RestTemplate rest = new RestTemplate(this.createFactory); return rest; }
RestTemplate
logback
裏單獨配一個debug
級別的logger
,把org.apache.http
下面的日誌定向到控制檯:<logger name="org.apache.http" level="DEBUG" additivity="false"> <appender-ref ref="STDOUT" /> </logger>
說點什麼呢,有任何建議,歡迎留言探討,本文源碼。apache
歡迎關注博主公衆號,第一時間推送最新文章json