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