方法一:拦截器

直接看RestTemplate提供的几个Get请求接口:getForEntity(),getForObject(),exchange(),并没有发现有设置请求头的地方,是不是就表明没法设置请求头了?

答案档案是能设置了,具体的使用思路有点类似mvc中的拦截器,自定义一个拦截器,然后在你实际发起请求时,拦截并设置request的请求头

注意到 RestTemplate 的父类InterceptingHttpAccessor提供了一个接收Interceptor的接口org.springframework.http.client.support.InterceptingHttpAccessor#setInterceptors,这个就是我们所需要的关键点(讲道理,除非事先就知道有这么个玩意,不然真让你去找,还不一定能找到)

所以第一步就是写一个ClientHttpRequestInterceptor类,添加请求头

public class UserAgentInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {
        HttpHeaders headers = request.getHeaders();
        headers.add(HttpHeaders.USER_AGENT,
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36");
        return execution.execute(request, body);
    }
}

下一步就是在创建RestTemplate对象之后,声明解释器并测试使用了

@Test
public void testGetHeader() {
    String url = "http://localhost:8080/agent?name=一灰灰Blog";
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setInterceptors(Collections.singletonList(new UserAgentInterceptor()));
    ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
    System.out.println(response.getStatusCode() + " | " + response.getBody());
}

首先在测试之前,先搭一个服务,简单判断agent,不满足条件的直接403, 后端mock代码如下

@ResponseBody
@RequestMapping(path = "agent")
public String agent(HttpServletRequest request, HttpServletResponse response,
        @RequestParam(value = "name", required = false) String name) throws IOException {
    String agent = request.getHeader(HttpHeaders.USER_AGENT);
    if (StringUtils.isEmpty(agent) || !agent.contains("WebKit")) {
        response.sendError(403, " illegal agent ");
    }
    return "welcome " + name;
}

上面执行后输出如下,添加请求头后正常返回

java 添加Request请求头header resttemplate添加请求头_spring boot

当然也需要对比下不设置agent的情况了,直接抛了一个异常出来了(说明,不显示覆盖User-Agent时,后端接收到的agent为: Java/1.8.0_171

java 添加Request请求头header resttemplate添加请求头_spring_02

上面虽然只给了设置User-Agent的例子,但是其他的请求头,都是可以放在自定义的Interceptor中添加进去的

方法二:exchange 方式

举例一:

另外还会关注到RestTemplate还提供了一个exchange方法,这个相当于一个公共的请求模板,使用姿势和get/post没有什么区别,只是可以由调用发自己来选择具体的请求方法

使用exchange对上面的post请求进行简单的替换如下, 基本上除了多一个参数之外没有什么区别了

@Test
public void testPostHeader() {
    String url = "http://localhost:8080/post";
    String email = "test@hhui.top";
    String nick = "一灰灰Blog";

    MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    params.add("email", email);
    params.add("nick", nick);

    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
            "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36");
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, request, String.class);
    System.out.println(response.getStatusCode() + " | " + response.getBody());
}

 

那么问题来了,为什么要有这个东西?或者说这个接口的提供可以带来什么好处?

  • 当你写一个公共的Rest工具类时,就比较方便了,底层统一,具体的方法由上层业务方选择即可
  • get可以通过这种方式直接添加请求头(也就是不需要第一种case中的自定义拦截器来塞入header,显然更加灵活)

举例二:

普通 GET请求,请求参数在路径中

/**
  * 普通 GET请求,请求参数在路径中
  */
 @Test
 public void getUser() {
     long userId = 32L;
     UserBean result = restTemplate.getForObject(
             "http://127.0.0.1:8280/user/{id}",
             UserBean.class,
             userId);
     logger.info("result={}", JSON.toJSONString(result));
 }

带header的GET请求

实际项目中远程接口调用很多时候是需要授权访问的,授权信息通常设置在http请求头里面,RestTemplate封装的get请求方法里面没有设置header的地方,那么我们是否对这种需要有header的get请求就不能使用RestTemplate了呢,当然不是。

那几个get请求封装方法重载程度较高,要往请求里面加请求头不容易,那我们就用里面的exchange方法,这个方法的封装程度是不高的,里面直接设置请求方式,并可以设置请求头。
 

/**
     * 带header的GET请求
     */
    @Test
    public void getHasHeader() {
        long userId = 32L;
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", "123");
        ResponseEntity<UserBean> response = restTemplate.exchange(
                "http://127.0.0.1:8280/user/{id}",
                HttpMethod.GET,
                new HttpEntity<String>(headers),
                UserBean.class,
                userId);
        logger.info("response={}", JSON.toJSONString(response.getBody()));
    }