【问题标题】:Spring RestTemplate, intercepting response before parsing to JsonSpring RestTemplate,在解析为Json之前拦截响应
【发布时间】:2016-02-02 13:58:21
【问题描述】:

我有一个 REST api,它在正文内容中响应一些额外的非 JSON 数据。这打破了 RestTemplate 和 jackson 的使用。可以在解析前截取http响应体吗?

我正在使用 RestTemplate.getForObject。

我查看了 RestTemplate,但找不到合适的方法。

【问题讨论】:

    标签: java json spring jackson resttemplate


    【解决方案1】:

    您可以尝试从您的控制器返回一个 ResponseEntity 并手动操作实体对象

    【讨论】:

      【解决方案2】:

      您可以尝试实现ClientHttpRequestInterceptor并将其分配给restTemplate。实现intercept方法:

      @Override
      public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes,
              ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
      
               ClientHttpResponse  response=clientHttpRequestExecution.execute(httpRequest, bytes);
               //...do magic with response body from getBody method
               return response;
      }
      

      您可能必须使用自己的实现扩展 AbstractClientHttpResponse 才能做到这一点。

      另一种选择是将来自 REST API 的响应视为字符串,然后根据需要格式化字符串并使用 ObjectMapper 将其显式映射到对象。

      那么在您的restTemplate 中,您将拥有:

       String result = restTemplate.getForObject(url, String.class, host);
       //..trim the extra stuff
       MyClass object=objectMapper.readValue(result, MyClass.class);
      

      另一种选择是实现您自己的HttpMessageConverter,它扩展AbstractJackson2HttpMessageConverter 并将其注册到restTemplate。在我看来,从 Spring 的角度来看,这将是最干净的

      【讨论】:

      • 当我试图弄清楚如何跳过 Gerrit 的魔法前缀行时,我点击了这个答案。由于 response.getBody() 是一个不可重置的 InputStream,我可以跳过 4 个字节并且正文变为有效的 JSON。因此,对于任何想要使用 Gerrit 的 API 的人,只需执行 response.getBody().skip(4);
      【解决方案3】:

      如果您不需要这些额外的属性,您可以添加:

          @JsonIgnoreProperties(ignoreUnknown = true)
      

      到你的映射类。

      来自docs

      定义是否可以忽略任何无法识别的属性 反序列化期间的属性。如果为真,则所有属性 unrecognized - 也就是说,没有接受它们的设置者或创建者 -- 在没有警告的情况下被忽略(尽管未知属性的处理程序, 如果有的话,仍然会被调用),无一例外。 对序列化没有任何影响。

      【讨论】:

      • 他说这是非 JSON 数据,这意味着它们根本不是属性。
      【解决方案4】:

      另一种方法是通过实现 ClientHttpRequestInterceptor 和 ClientHttpResponse 来解开响应。

              @Component
              public class MyInterceptor implements ClientHttpRequestInterceptor {
      
              @Autowired
              Function<ClientHttpResponse, MyResponseWrapper> responseWrapperBeanFactory;
      
              @Autowired
              MyRequestAdvice requestAdvice;
      
              @Override
                public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
                  byte[] wrappedBody = requestAdvice.wrapRequest(bytes);
                  ClientHttpResponse res = clientHttpRequestExecution.execute(httpRequest, wrappedBody);
                  return responseWrapperBeanFactory.apply(res);
              }    
      
             }
      

      这是 MyResponseWrapper 的 bean 配置:

      @Bean
      Function<ClientHttpResponse, MyResponseWrapper> responseWrapperBeanFactory() {
          return this::getMyResponseWrapper;
      }
      
      @Bean
      @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
      public MyResponseWrapper getMyResponseWrapper(ClientHttpResponse originalResponse) {
          return new MyResponseWrapper(originalResponse);
      }
      
      @Bean
      public RestTemplate restTemplate(@Autowired MyInterceptor interceptor) {
          RestTemplate t = new RestTemplate();
          t.setInterceptors(Arrays.asList(interceptor));
          // other setup code
      
          return t;
      }
      

      这是 ClientHttpResponse 的实现:

      public class MyResponseWrapper implements ClientHttpResponse {
      
          private byte[] filteredContent;
          private ByteArrayInputStream responseInputStream;
      
      
          private ClientHttpResponse originalResponse;
      
          public MyResponseWrapper(ClientHttpResponse originalResponse) {
              this.originalResponse = originalResponse;
      
              try {
                  filteredContent = MyContentUnwrapper.unwrapResponse(originalResponse.getBody().readAllBytes());
              } catch (Exception e) {
                  throw new RuntimeException("There was a problem reading/decoding the response coming from the service ", e);
              }
          }
      
          @Override
          public HttpStatus getStatusCode() throws IOException {
              return originalResponse.getStatusCode();
          }
      
          @Override
          public int getRawStatusCode() throws IOException {
              return originalResponse.getRawStatusCode();
          }
      
          @Override
          public String getStatusText() throws IOException {
              return originalResponse.getStatusText();
          }
      
          @Override
          public void close() {
              if (responseInputStream != null) {
                  try {
                      responseInputStream.close();
                  } catch (IOException e) { /* so long */}
              }
          }
      
          @Override
          public InputStream getBody() throws IOException {
              if (responseInputStream == null) {
                  responseInputStream = new ByteArrayInputStream(filteredContent);
              }
              return responseInputStream;
          }
      
          @Override
          public HttpHeaders getHeaders() {
              return originalResponse.getHeaders();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-08
        • 1970-01-01
        • 2014-10-19
        • 2014-04-16
        • 1970-01-01
        • 2019-12-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多