首页 > 其他分享 >Springboot整合RestTemplate发送http请求

Springboot整合RestTemplate发送http请求

时间:2022-10-09 18:08:53浏览次数:74  
标签:http 请求 url restTemplate RestTemplate String new Springboot


据技术选型总结常见的三种方式发送http请求,本文介绍Springboot整合RestTemplate发送http请求方式,其他两种如下链接

java原生发送http请求_程序三两行的博客

HttpClient和OkHttp发送http请求_程序三两行的博客

​1、简述RestTemplate​

​RestTemplate​​​是一个执行​​HTTP​​​请求的同步阻塞式工具类,它仅仅只是在 ​​HTTP​​ 客户端库(例如 JDK HttpURLConnection,Apache HttpComponents,okHttp 等)基础上,封装了更加简单易用的模板方法 API,方便程序员利用已提供的模板方法发起网络请求和处理

2、配置

如果当前项目不是​​Spring​​​项目,加入​​spring-web​​​包,即可引入​​RestTemplate​​类

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>

 编写一个单元测试类,使用​​RestTemplate​​​发送一个​​GET​​请求,看看程序运行是否正常

@Test
public void simpleTest() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://jsonplaceholder.typicode.com/posts/1";
String str = restTemplate.getForObject(url, String.class);
System.out.println(str);
}

Spring 环境下使用 RestTemplate,只需有以下jar就可使用

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

 把 RestTemplate交给spring管理

package com.rails.travel.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
* RestTemplate配置类
*/
@Configuration
public class RestTemplateConfig {


//2.0后使用下面没有注掉的方式 在注入的同时设置连接时间,这种注释的也可以,但是没有设置超时时间
/*@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}*/

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}

@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);//单位为ms
factory.setConnectTimeout(5000);//单位为ms
return factory;
}
}

这种初始化方法,是使用了​​JDK​​​自带的​​HttpURLConnection​​​作为底层​​HTTP​​客户端实现。

当然,我们还可以修改​​RestTemplate​​​默认的客户端,例如将其改成​​HttpClient​​客户端,方式如下

@Configuration
public class RestTemplateConfig {


/**
* 没有实例化RestTemplate时,初始化RestTemplate
* @return
*/
@ConditionalOnMissingBean(RestTemplate.class)
@Bean
public RestTemplate restTemplate(){
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
return restTemplate;
}

/**
* 使用HttpClient作为底层客户端
* @return
*/
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5000;
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.setSocketTimeout(timeout)
.build();
CloseableHttpClient client = HttpClientBuilder
.create()
.setDefaultRequestConfig(config)
.build();
return new HttpComponentsClientHttpRequestFactory(client);
}

}

从开发人员的反馈,和网上的各种​​HTTP​​​客户端性能以及易用程度评测来看,​​OkHttp​​​ 优于 ​​Apache​​​的​​HttpClient​​​、​​Apache​​​的​​HttpClient​​​优于​​HttpURLConnection​​。

因此,我们还可以通过如下方式,将底层的​​http​​​客户端换成​​OkHttp​​!

/**
* 使用OkHttpClient作为底层客户端
* @return
*/
private ClientHttpRequestFactory getClientHttpRequestFactory(){
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.build();
return new OkHttp3ClientHttpRequestFactory(okHttpClient);
}

3、使用

​RestTemplate​​​最大的特色就是对各种网络请求方式做了包装,能极大的简化开发人员的工作量,下面我们以​​GET​​​、​​POST​​​、​​PUT​​​、​​DELETE​​​、​​文件上传与下载​​​为例,分别介绍各个​​API​​的使用方式!

GET 请求

在 RestTemplate 中,和 GET 请求相关的方法有如下几个:

Springboot整合RestTemplate发送http请求_spring

这里的方法一共有两类,getForEntity 和 getForObject,每一类有三个重载方法

二者的主要区别在于,​​getForObject()​​​返回值是​​HTTP​​协议的响应体。

​getForEntity()​​​返回的是​​ResponseEntity​​​,​​ResponseEntity​​​是对​​HTTP​​​响应的封装,除了包含响应体,还包含​​HTTP​​​状态码、​​contentType​​​、​​contentLength​​​、​​Header​​等信息。

getForEntity

既然 RestTemplate 发送的是 HTTP 请求,那么在响应的数据中必然也有响应头,如果开发者需要获取响应头的话,那么就需要使用 getForEntity 来发送 HTTP 请求,此时返回的对象是一个 ResponseEntity 的实例。这个实例中包含了响应数据以及响应头

第一个参数是 url ,url 中有一个占位符 {1} ,如果有多个占位符分别用 {2} 、 {3} … 去表示,第二个参数是接口返回的数据类型,最后是一个可变长度的参数,用来给占位符填值。在返回的 ResponseEntity 中,可以获取响应头中的信息,其中 getStatusCode 方法用来获取响应状态码, getBody 方法用来获取响应数据, getHeaders 方法用来获取响应头

String url = "http://localhost/hello?name={1}";
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, "张三");
StringBuffer sb = new StringBuffer();
HttpStatus statusCode = responseEntity.getStatusCode();
String body = responseEntity.getBody();

 当然,这里参数的传递除了这一种方式之外,还有另外两种方式,也就是 getForEntity 方法的另外两个重载方法。

第一个是占位符不使用数字,而是使用参数的 key,同时将参数放入到一个 map 中。map 中的 key 和占位符的 key 相对应,map 中的 value 就是参数的具体值,例如还是上面的请求,利用 map 来传递参数,请求方式如下:

Map<String, Object> map = new HashMap<>();
String url = "http://" + host + ":" + port + "/hello?name={name}";
map.put("name", name);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map);

这种方式传参可能看起来更直观一些。

第二个是使用 Uri 对象,使用 Uri 对象时,参数可以直接拼接在地址中,例如下面这样:

String url = "http://" + host + ":" + port + "/hello?name="+ URLEncoder.encode(name,"UTF-8");
URI uri = URI.create(url);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);

需要注意的是,这种传参方式,参数如果是中文的话,需要对参数进行编码,使用 ​​URLEncoder.encode​​ 方法来实现。

getForObject

getForObject 方法和 getForEntity 方法类似,getForObject 方法也有三个重载的方法,参数和 getForEntity 一样;主要说下 getForObject 和 getForEntity 的差异,这两个的差异主要体现在返回值的差异上, getForObject 的返回值就是服务提供者返回的数据,使用 getForObject 无法获取到响应头。例如,还是上面的请求,利用 getForObject 来发送 HTTP 请求,结果如下:

String url = "http://" + host + ":" + port + "/hello?name=" + URLEncoder.encode(name, "UTF-8");
URI uri = URI.create(url);
String s = restTemplate.getForObject(uri, String.class);

 注意,这里返回的 s 就是 provider 的返回值,如果开发者只关心 provider 的返回值,并不关系 HTTP 请求的响应头,那么可以使用该方法。

POST 请求

和 GET 请求相比,RestTemplate 中的 POST 请求多了一个类型的方法,如下:

Springboot整合RestTemplate发送http请求_http_02

​postForEntity()​​​返回全部的信息,​​postForObject()​​​方法返回​​body​​对象 

可以看到,post 请求的方法类型除了 postForEntity 和 postForObject 之外,还有一个 postForLocation。这里的方法类型虽然有三种,但是这三种方法重载的参数基本是一样的,因此这里我还是以 postForEntity 方法为例,来剖析三个重载方法的用法,最后再重点说下 postForLocation 方法。

postForEntity

在 POST 请求中,参数的传递可以是 key/value 的形式,也可以是 JSON 数据,分别来看:

a: 传递 key/value 形式的参数  

int port = instance.getPort();
String url = "http://" + host + ":" + port + "/hello2";
MultiValueMap map = new LinkedMultiValueMap();
map.add("name", name);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, map, String.class);
return responseEntity.getBody();

postForEntity 方法第一个参数是请求地址,第二个参数 map 对象中存放着请求参数 key/value,第三个参数则是返回的数据类型。当然这里的第一个参数 url 地址也可以换成一个 Uri 对象,效果是一样的。这种方式传递的参数是以 key/value 形式传递的,在 post 请求中,也可以按照 get 请求的方式去传递 key/value 形式的参数,传递方式和 get 请求的传参方式基本一致

String host = "myhost";
int port = "2020";
String url = "http://" + host + ":" + port + "/hello2?name={1}";
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, null, String.class,name);
return responseEntity.getBody();

 此时第二个参数可以直接传一个 null。

b:传递 JSON 数据

上面介绍的是 post 请求传递 key/value 形式的参数,post 请求也可以直接传递 json 数据,在 post 请求中,可以自动将一个对象转换成 json 进行传输,数据到达 provider 之后,再被转换为一个对象。具体操作步骤如下:

String url = "http://" + host + ":" + port + "/user";
User u1 = new User();
u1.setUsername("李四");
u1.setAddress("深圳");
ResponseEntity<User> responseEntity = restTemplate.postForEntity(url, u1, User.class);
return responseEntity.getBody();

唯一的区别就是第二个参数的类型不同,这个参数如果是一个 MultiValueMap 的实例,则以 key/value 的形式发送,如果是一个普通对象,则会被转成 json 发送。

postForObject

postForObject 和 postForEntity 基本一致,就是返回类型不同而已

postForLocation

postForLocation 方法的返回值是一个 Uri 对象,因为 POST 请求一般用来添加数据,有的时候需要将刚刚添加成功的数据的 URL 返回来,此时就可以使用这个方法,一个常见的使用场景如用户注册功能,用户注册成功之后,可能就自动跳转到登录页面了,此时就可以使用该方法。

String url = "http://" + host + ":" + port + "/register";
MultiValueMap map = new LinkedMultiValueMap();
map.add("username", "李四");
map.add("address", "深圳");
URI uri = restTemplate.postForLocation(url, map);
String s = restTemplate.getForObject(uri, String.class);
return s;

 注意:postForLocation 方法返回的 Uri 实际上是指响应头的 Location 字段,所以,provider 中 register 接口的响应头必须要有 Location 字段(即请求的接口实际上是一个重定向的接口),否则 postForLocation 方法的返回值为null

PUT 请求

只要将 GET 请求和 POST 请求搞定了,接下来 PUT 请求就会容易很多了,PUT 请求本身方法也比较少,只有三个,如下:

Springboot整合RestTemplate发送http请求_spring_03

这三个重载的方法其参数其实和 POST 是一样的,可以用 key/value 的形式传参,也可以用 JSON 的形式传参,无论哪种方式,都是没有返回值的

String host ="myhost";
int port = "8080";
String url1 = "http://" + host + ":" + port + "/user/name";
String url2 = "http://" + host + ":" + port + "/user/address";
MultiValueMap map = new LinkedMultiValueMap();
map.add("username", "李四");
map.add("address", "深圳");
restTemplate.put(url1, map);
User u1 = new User();
u1.setAddress("广州");
u1.setUsername("张三");
restTemplate.put(url2, u1);

DELETE 请求

和 PUT 请求一样,DELETE 请求也是比较简单的,只有三个方法,如下:

Springboot整合RestTemplate发送http请求_spring boot_04

不同于 POST 和 PUT ,DELETE 请求的参数只能在地址栏传送,可以是直接放在路径中,也可以用 key/value 的形式传递,当然,这里也是没有返回值的。

String host = "myhost";
int port = "8080";
String url1 = "http://" + host + ":" + port + "/user/{1}";
String url2 = "http://" + host + ":" + port + "/user/?username={username}";
Map<String,String> map = new HashMap<>();
map.put("username", "李四");
restTemplate.delete(url1, 99);
restTemplate.delete(url2, map);

这里参数的传递和 GET 请求基本一致

通用方法 exchange

如果以上方法还不满足你的要求。在​​RestTemplate​​​工具类里面,还有一个​​exchange​​​通用协议请求方法,它可以发送​​GET​​​、​​POST​​​、​​DELETE​​​、​​PUT​​​、​​OPTIONS​​​、​​PATCH​​​等等​​HTTP​​方法请求

为什么说它通用呢?因为这个方法需要你在调用的时候去指定请求类型,即它既能做 GET 请求,也能做 POST 请求,也能做其它各种类型的请求。如果开发者需要对请求进行封装,使用它再合适不过了

@GetMapping("/hello12")
public void hello12() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/customheader";
HttpHeaders headers = new HttpHeaders();
headers.add("cookie","justdojava");
HttpEntity<MultiValueMap<String,String>> request = new HttpEntity<>(null,headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, request, String.class);
System.out.println(responseEntity.getBody());
}

采用​​exchange​​方法,可以满足各种场景下的请求操作 

文件上传与下载

除了经常用到的​​get​​​和​​post​​​请求以外,还有一个我们经常会碰到的场景,那就是文件的上传与下载,如果采用​​RestTemplate​​,该怎么使用呢?

案例如下,具体实现细节参考代码注释!

文件上传

@RestController
public class FileUploadController {


private static final String UPLOAD_PATH = "/springboot-frame-example/springboot-example-resttemplate/";

/**
* 文件上传
* @param uploadFile
* @return
*/
@RequestMapping(value = "upload", method = RequestMethod.POST)
public ResponseBean upload(@RequestParam("uploadFile") MultipartFile uploadFile,
@RequestParam("userName") String userName) {
// 在 uploadPath 文件夹中通过用户名对上传的文件归类保存
File folder = new File(UPLOAD_PATH + userName);
if (!folder.isDirectory()) {
folder.mkdirs();
}

// 对上传的文件重命名,避免文件重名
String oldName = uploadFile.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));

//定义返回视图
ResponseBean result = new ResponseBean();
try {
// 文件保存
uploadFile.transferTo(new File(folder, newName));
result.setCode("200");
result.setMsg("文件上传成功,方法:upload,文件名:" + newName);
} catch (IOException e) {
e.printStackTrace();
result.setCode("500");
result.setMsg("文件上传失败,方法:upload,请求文件:" + oldName);
}
return result;
}
}

 测试

@Autowired
private RestTemplate restTemplate;

/**
* 文件上传,post请求
*/
@Test
public void upload(){
//需要上传的文件
String filePath = "/Users/panzhi/Desktop/Jietu20220205-194655.jpg";

//请求地址
String url = "http://localhost:8080/upload";

// 请求头设置,multipart/form-data格式的数据
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

//提交参数设置
MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
param.add("uploadFile", new FileSystemResource(new File(filePath)));
//服务端如果接受额外参数,可以传递
param.add("userName", "张三");

// 组装请求体
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(param, headers);

//发起请求
ResponseBean responseBean = restTemplate.postForObject(url, request, ResponseBean.class);
System.out.println(responseBean.toString());
}

文件下载

@RestController
public class FileUploadController {


private static final String UPLOAD_PATH = "springboot-frame-example/springboot-example-resttemplate/";


/**
* 带参的get请求(restful风格)
* @return
*/
@RequestMapping(value = "downloadFile/{userName}/{fileName}", method = RequestMethod.GET)
public void downloadFile(@PathVariable(value = "userName") String userName,
@PathVariable(value = "fileName") String fileName,
HttpServletRequest request,
HttpServletResponse response) throws Exception {

File file = new File(UPLOAD_PATH + userName + File.separator + fileName);
if (file.exists()) {
//获取文件流
FileInputStream fis = new FileInputStream(file);
//获取文件后缀(.png)
String extendFileName = fileName.substring(fileName.lastIndexOf('.'));
//动态设置响应类型,根据前台传递文件类型设置响应类型
response.setContentType(request.getSession().getServletContext().getMimeType(extendFileName));
//设置响应头,attachment表示以附件的形式下载,inline表示在线打开
response.setHeader("content-disposition","attachment;fileName=" + URLEncoder.encode(fileName,"UTF-8"));
//获取输出流对象(用于写文件)
OutputStream os = response.getOutputStream();
//下载文件,使用spring框架中的FileCopyUtils工具
FileCopyUtils.copy(fis,os);
}
}
}
@Autowired
private RestTemplate restTemplate;

/**
* 小文件下载
* @throws IOException
*/
@Test
public void downloadFile() throws IOException {
String userName = "张三";
String fileName = "c98b677c-0948-46ef-84d2-3742a2b821b0.jpg";
//请求地址
String url = "http://localhost:8080/downloadFile/{1}/{2}";

//发起请求,直接返回对象(restful风格)
ResponseEntity<byte[]> rsp = restTemplate.getForEntity(url, byte[].class, userName,fileName);
System.out.println("文件下载请求结果状态码:" + rsp.getStatusCode());

// 将下载下来的文件内容保存到本地
String targetPath = "/Users/panzhi/Desktop/" + fileName;
Files.write(Paths.get(targetPath), Objects.requireNonNull(rsp.getBody(), "未获取到下载文件"));
}

 这种下载方法实际上是将下载文件一次性加载到客户端本地内存,然后从内存将文件写入磁盘。这种方式对于小文件的下载还比较适合,如果文件比较大或者文件下载并发量比较大,容易造成内存的大量占用,从而降低应用的运行效率。

大文件下载

@Autowired
private RestTemplate restTemplate;

/**
* 大文件下载
* @throws IOException
*/
@Test
public void downloadBigFile() throws IOException {
String userName = "张三";
String fileName = "c98b677c-0948-46ef-84d2-3742a2b821b0.jpg";
//请求地址
String url = "http://localhost:8080/downloadFile/{1}/{2}";

//定义请求头的接收类型
RequestCallback requestCallback = request -> request.getHeaders()
.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));

//对响应进行流式处理而不是将其全部加载到内存中
String targetPath = "/Users/panzhi/Desktop/" + fileName;
restTemplate.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
Files.copy(clientHttpResponse.getBody(), Paths.get(targetPath));
return null;
}, userName, fileName);
}

这种下载方式的区别在于:

  • 设置了请求头​​APPLICATION_OCTET_STREAM​​,表示以流的形式进行数据加载
  • ​RequestCallback​​​结合​​File.copy​​保证了接收到一部分文件内容,就向磁盘写入一部分内容。而不是全部加载到内存,最后再写入磁盘文件。

在下载大文件时,例如​​excel​​​、​​pdf​​​、​​zip​​等等文件,特别管用,

4、自定义设置

手动指定转换器(HttpMessageConverter)

我们知道,调用reseful接口传递的数据内容是json格式的字符串,返回的响应也是json格式的字符串。然而​​restTemplate.postForObject​​​方法的请求参数​​RequestBean​​​和返回参数​​ResponseBean​​​却都是java类。是​​RestTemplate​​​通过​​HttpMessageConverter​​自动帮我们做了转换的操作。

默认情况下​​RestTemplate​​​自动帮我们注册了一组​​HttpMessageConverter​​​用来处理一些不同的​​contentType​​​的请求。
如​​​StringHttpMessageConverter​​​来处理​​text/plain​​​;​​MappingJackson2HttpMessageConverter​​​来处理​​application/json​​​;​​MappingJackson2XmlHttpMessageConverter​​​来处理​​application/xml​​​。
你可以在​​​org.springframework.http.converter​​​包下找到所有spring帮我们实现好的转换器。
如果现有的转换器不能满足你的需求,你还可以实现​​​org.springframework.http.converter.HttpMessageConverter​​​接口自己写一个。详情​​参考官方api​​。

选好了​​HttpMessageConverter​​​后怎么把它注册到我们的​​RestTemplate​​中呢。

RestTemplate restTemplate = new RestTemplate();
//获取RestTemplate默认配置好的所有转换器
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
//默认的MappingJackson2HttpMessageConverter在第7个 先把它移除掉
messageConverters.remove(6);
//添加上GSON的转换器
messageConverters.add(6, new GsonHttpMessageConverter());

这个简单的例子展示了如何使用​​GsonHttpMessageConverter​​​替换掉默认用来处理​​application/json​​​的​​MappingJackson2HttpMessageConverter​​。

设置底层连接方式

要创建一个​​RestTemplate​​​的实例,您可以像上述例子中简单地调用默认的无参数构造函数。这将使用​​java.net​​​包中的标准Java类作为底层实现来创建HTTP请求。
但很多时候我们需要像传统的​​​HttpClient​​​那样设置HTTP请求的一些属性。​​RestTemplate​​​使用了一种很偷懒的方式实现了这个需求,那就是直接使用一个​​HttpClient​​作为底层实现......

//生成一个设置了连接超时时间、请求超时时间、异常最大重试次数的httpClient
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(10000).setConnectTimeout(10000).setSocketTimeout(30000).build();
HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(config).setRetryHandler(new DefaultHttpRequestRetryHandler(5, false));
HttpClient httpClient = builder.build();
//使用httpClient创建一个ClientHttpRequestFactory的实现
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
//ClientHttpRequestFactory作为参数构造一个使用作为底层的RestTemplate
RestTemplate restTemplate = new RestTemplate(requestFactory);

设置拦截器(ClientHttpRequestInterceptor)

有时候我们需要对请求做一些通用的拦截设置,这就可以使用拦截器进行处理。拦截器需要我们实现​​org.springframework.http.client.ClientHttpRequestInterceptor​​接口自己写。

举个简单的例子,写一个在header中根据请求内容和地址添加令牌的拦截器。

public class TokenInterceptor implements ClientHttpRequestInterceptor
{
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
{
//请求地址
String checkTokenUrl = request.getURI().getPath();
//token有效时间
int ttTime = (int) (System.currentTimeMillis() / 1000 + 1800);
//请求方法名 POST、GET等
String methodName = request.getMethod().name();
//请求内容
String requestBody = new String(body);
//生成令牌 此处调用一个自己写的方法,有兴趣的朋友可以自行google如何使用ak/sk生成token,此方法跟本教程无关,就不贴出来了
String token = TokenHelper.generateToken(checkTokenUrl, ttTime, methodName, requestBody);
//将令牌放入请求header中
request.getHeaders().add("X-Auth-Token",token);

return execution.execute(request, body);
}
}

创建​​RestTemplate​​实例的时候可以这样向其中添加拦截器

RestTemplate restTemplate = new RestTemplate();
//向restTemplate中添加自定义的拦截器
restTemplate.getInterceptors().add(new TokenInterceptor());

设置请求头

有的时候我们会有一些特殊的需求,例如模拟 cookie ,此时就需要我们自定义请求头了。自定义请求头可以通过拦截器的方式来实现(下篇文章我们会详细的说这个拦截器)。定义拦截器、自动修改请求数据、一些身份认证信息等,都可以在拦截器中来统一处理。具体操作步骤如下:

首先在 provider 中定义一个接口,在接口中获取客户端传来的 cookie 数据,如下:

@GetMapping("/customheader")
public String customHeader(HttpServletRequest req) {
return req.getHeader("cookie");
}

这里简单处理,将客户端传来的 cookie 拿出来后再返回给客户端,然后在 consumer 中添加如下接口来测试:

@GetMapping("/hello11")
public void hello11() {
List<ServiceInstance> list = discoveryClient.getInstances("provider");
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/customheader";
restTemplate.setInterceptors(Collections.singletonList(new ClientHttpRequestInterceptor() {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
headers.add("cookie","justdojava");
return execution.execute(request,body);
}
}));
String s = restTemplate.getForObject(url, String.class);
System.out.println(s);
}

这里通过调用 RestTemplate 的 setInterceptors 方法来给它设置拦截器,拦截器也可以有多个,我这里只有一个。在拦截器中,将请求拿出来,给它设置 cookie ,然后调用 execute 方法让请求继续执行。此时,在 ​​/customheader​​ 接口中,就能获取到 cookie了。

标签:http,请求,url,restTemplate,RestTemplate,String,new,Springboot
From: https://blog.51cto.com/u_11334685/5740960

相关文章

  • Springboot如何发送邮件
    邮件发送过程简介依赖 配置文件可以配置的属性值例如[email protected]=123456#授权码spring.mail.host=smtp.qq.com#smtp地址spring......
  • 从SpringBoot启动,阅读源码设计
    服务启动堪称Spring源码设计的答案;一、背景说明初学SpringBoot框架时,第一次启动服务,直呼什么鬼?只需要简单的几步配置,几个核心的注解,就可以快速实现工程的搭建和运行;虽......
  • SpringBoot启动配置原理
    https://cloud.tencent.com/developer/article/1802822?from=article.detail.1449134#SpringBoot启动配置原理几个重要的事件回调机制配置在META-INF/spring.factori......
  • SpringBoot实现Mysql读写分离
    前言在高并发的场景中,关于数据库都有哪些优化的手段?常用的有以下的实现方法:读写分离、加缓存、主从架构集群、分库分表等,在互联网应用中,大部分都是读多写少的场景,设置......
  • 如何屏蔽掉SpringBoot项目中自己不想使用的模块
    最近在修改离职同事几年前的代码,没有文档,向正常启动跑个单元测试都困难。比如我这次想测试一下我写的查询,结果单元测试运行的时候就提示Mailserverisnotavailable,当......
  • jmeter BeanShell PostProcessor 获取http请求的入参,存入CSV
    1、在http请求前新建一个jmeterBeanShellPostProcessor,其与http请求同在一个线程组内。  2、下载fastjson-2.0.14.jar包放在jmeter的lib目录下 下载路径为:http......
  • SpringBoot启动原理
    https://cloud.tencent.com/developer/article/1747423?from=article.detail.1449134背景1>大家都知道SpringBoot是通过main函数启动的,这里面跟踪代码到处都没有找到whi......
  • 【SpringBoot】SpringBoot 项目编写顺序
    创建项目1、创建maven/SpringBoot 项目2、添加依赖3、创建SpringBoot引导类Application 项目基本结构引导类Application同级目录下创建模块包   在......
  • 【SpringBoot】常用注解
    @Controller标记在类上面,类就是一个Controller对象;只是定义了一个控制器类。@RestController写在Controller类之前,添加该注解即可返回JSON格式的数据;@RestController......
  • Springboot整合es
    参考文章链接​​SpringBoot操作ES,实现各种骚操作查询-知乎​​二、整合方式boot整合es三种方式SpringBoot整合ES的三种方式(API、RESTClient、Data-ES)_jacksonary的博客......