在RestTemplate通过拦截器修改请求和响应 - Aditya


Spring中通常使用拦截器来拦截Controller 或自创建端点的请求,或者拦截由 RestTemplate 完成的其他(第 3 方)api 调用。本文介绍了后一种情况,我们将拦截器应用于 restTemplate 以修改用于调用第 3 方 api 的请求-响应。
本文将通过对请求正文应用加密和对响应正文应用解密来演示相同的内容。Interceptor 将即时应用加密-解密。原因:如果不是通过拦截器完成的,则需要在 Req-Res 对象上应用这些修改(加密-解密),在我们必须进行需要加密的 REST 调用的每个地方。
相应的拦截器将应用于 restTemplate,一个用于进行 REST 调用的 spring 实现的 bean。
们将使用常规POJO作为请求-响应对象。拦截器将作用于这些,执行修改操作(加密/解密)。从而消除了开发人员的责任,在每次请求时都执行此操作,出于演示目的,加密-解密以一种非常幼稚的方式使用。
 
方法:
我们将在项目中使用两个 Rest Template对象。

  • a) 一个是普通格式(普通的 spring bean 对象)。— 在需要进行常规 REST 调用时使用。
  • b) 另一个 restTemplate spring bean将应用拦截器。— 当需要对请求-响应对象应用加密-解密时使用

@Bean
@Primary
// This RestTemplate bean will be used for regular REST call
public RestTemplate getPlainRestTemplate() {
 RestTemplate restTemplate =
   new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
 return restTemplate;
}


@Bean(
"interceptedRestTemplate")
public RestTemplate getInterceptedRestTemplate() {
 RestTemplate restTemplate =
   new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
 List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
 interceptors.add(interceptor);
 restTemplate.setInterceptors(interceptors);
 return restTemplate;
}

  • 1 . 拦截器将提取请求对象并对其应用所需的修改(加密)。
  • 2. 然后我们执行请求。即,进行REST 调用
  • 3. 收到作为ClientHttpResponse 对象的请求后,我们将首先执行响应修改(解密)。
  • 4. 因此,我们打算将收到的响应转换为解密的响应。
  • 5. 现在,创建一个新的 ClientHttpResponse 对象。将decryptedResponse 复制到它的主体和其他字段,例如要从receivedResponse 对象填充的标头。
  • 6. 返回 ClientHttpResponse 这个新填充的对象作为响应。

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    String reqBody = new String(body);
    byte[] encryptedRequestBody = service.doEncryption(reqBody);
    ClientHttpResponse response = execution.execute(request, encryptedRequestBody);
    String responseBody = new String(response.getBody().readAllBytes());
    byte[] decryptedResponseBodyBytes = service.doDecryption(responseBody);
    String decryptedResponseBody = new String(decryptedResponseBodyBytes);

    // prepare modified response
    ClientHttpResponse decryptedRes = new ClientHttpResponse() {
        @Override
        public HttpHeaders getHeaders() {
            return response.getHeaders();
        }

        @Override
        public InputStream getBody() throws IOException {
           
// The expected modified response body to be populated here
            return new ByteArrayInputStream(decryptedResponseBody.getBytes());
        }

        @Override
        public HttpStatus getStatusCode() throws IOException {
            return response.getStatusCode();
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return response.getRawStatusCode();
        }

        @Override
        public String getStatusText() throws IOException {
            return response.getStatusText();
        }

        @Override
        public void close() {

        }
    };
    return decryptedRes;
}

Sample Project at GITHUB:https://github.com/aditya-rewari/InterceptorPOC.git
Interceptor Code snippet(GIST):https://gist.github.com/aditya-rewari/1994eacbddab1e895d10686d23b24f48