Resttemplate利用拦截器配置请求

Posted by BY Blog on December 11, 2018

RestTemplate利用拦截器配置请求

Spring RestTemplate经常被用作客户端向Restful API发送各种请求,也许你也碰到过这种需求,很多请求都需要用到相似或者相同的Http Header。如果在每次请求之前都把Header填入HttpEntity/RequestEntity,这样的代码会显得十分冗余。

Spring提供了ClientHttpRequestInterceptor接口,可以对请求进行拦截,并在其被发送至服务端之前修改请求或是增强相应的信息。拦截器的实现主要分为如下几个步骤:

  • 定义一个类RestTemplateInterceptor,实现ClientHttpRequestInterceptor
  • 生成一个特殊的RestTemplate,其拦截器为RestTemplateInterceptor
  • 使用RestTemplate调用请求

下面以一个实例来介绍拦截器的使用

定义RestTemplateInterceptor
@Component
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // 向头部中加入一些信息
        addRequestHeader(request);
        // restTemplate调用其他请求
        ClientHttpResponse response = execution.execute(request, body);
        // 在返回之前也可以做一些其他的操作,如cookie管理。关于手动管理cookie,后面也会介绍
        return response;
    }

    // 向头部中加入一些信息
    private void addRequestHeader(HttpRequest request) {
        HttpHeaders headers = request.getHeaders();

        // 设置请求类型
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.add("testId","add by interceptor");
    }
}

这个类实现了ClientHttpRequestInterceptor的intercept接口,并定义了一个将testId加入header中的方法addRequestHeader中。

生成特殊RestTemplate
@Configuration
public class RestTemplateConfig {
    @Autowired
    private RestTemplateInterceptor restTemplateInterceptor;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        // 设置restTemplate的interceptor属性
        restTemplate.setInterceptors(Arrays.asList(restTemplateInterceptor));
        return restTemplate;
    }
}
编写controller类调用
@RestController
@RequestMapping(value = "/{version}/interceptor")
public class InterceperTestController {
    @Autowired
    private BasicService basicService;

    /**
     * 被调方
     */
    @PostMapping(value = "/server", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public CommonResponseBody beCalled(@PathVariable("version") String version,
                                       @RequestHeader("testId") String testId) {
        return new CommonResponseBody(0, (Object)testId);
    }

    /**
     * 调用方
     */
    @PostMapping(value = "/client")
    public CommonResponseBody call(@PathVariable("version") String version) {
        return basicService.postProxy(version, "interceptor", "server", null, null, CommonResponseBody.class).getBody();
    }

}

在上面,主要包含两个接口,/client接口调用了/server接口。/server接口需要一个名为testId的请求头,但是/client并没有传入任何信息,也可以调用/server成功,这是因为在调用/server之前,拦截器在请求头中加入了testId属性。

测试

测试

这时,如果注释掉headers.add("testId","add by interceptor"); , 再次测试将会出现如下错误:

测试

辅助类

在上述实现当中,实现了一个辅助类BasicService,用来实现通用的post、get透传。

@Service
public class BasicService {

    @Autowired
    private RestTemplate restTemplate;

    private static final String URI_FORMAT = "http://localhost:18080/%s/%s/%s";

    /**
     * 通用post透传接口
     *
     * @param version      版本号
     * @param cmd          一级命令
     * @param subcmd       二级命令
     * @param headers      请求头
     * @param body         请求体
     * @param responseType 返回类型
     * @param <T>
     * @return
     */
    public <T> ResponseEntity<T> postProxy(String version, String cmd, String subcmd, HttpHeaders headers, Object body, Class<T> responseType) {
        String uri = String.format(URI_FORMAT, version, cmd, subcmd);
        HttpEntity request = new HttpEntity<>(body, headers);
        ResponseEntity<T> responseEntity = restTemplate.postForEntity(uri, request, responseType);
        return responseEntity;
    }

    /**
     * 通用get透传接口
     *
     * @param version 版本号
     * @param cmd 一级命令
     * @param subcmd 二级命令
     * @param headers 请求头
     * @param responseType 返回类型
     * @param <T>
     * @return
     */
    public <T> ResponseEntity<T> getProxy(String version, String cmd, String subcmd, HttpHeaders headers, Class<T> responseType) {
        String uri = String.format(URI_FORMAT, version, cmd, subcmd);
        HttpEntity request = new HttpEntity<>(headers);
        ResponseEntity<T> responseEntity = restTemplate.exchange(uri, HttpMethod.GET, request, responseType);
        return responseEntity;
    }

}
参考博客

https://www.jianshu.com/p/deb5e5efb724

完整代码:https://github.com/HorizonLiu/http_servlet.git