为啥我的自定义 ClientHttpRequestInterceptor 响应为空

Posted

技术标签:

【中文标题】为啥我的自定义 ClientHttpRequestInterceptor 响应为空【英文标题】:Why my custom ClientHttpRequestInterceptor with empty response为什么我的自定义 ClientHttpRequestInterceptor 响应为空 【发布时间】:2018-10-06 00:21:59 【问题描述】:

我为我的自定义日志拦截器做了以下操作

public class HttpLoggingInterceptor implements ClientHttpRequestInterceptor 
    private final static Logger log = LoggerFactory.getLogger(HttpLoggingInterceptor.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException 
        logRequest(request, body);
        ClientHttpResponse response = execution.execute(request, body);
        logResponse(response);
        return response;
    

    private void logRequest(HttpRequest request, byte[] body) throws IOException 
        log.info("Request URI : , Method : , Headers : , Request body : ", request.getURI(), request.getMethod(), request.getHeaders(), new String(body, "UTF-8"));

    

    private void logResponse(ClientHttpResponse response) throws IOException 
        log.info("Response Status code : , Status text : , Headers : , Response body: ", response.getStatusCode(), response.getStatusText(), response.getHeaders(), StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
    

我将拦截器设置为 restTemplate

   @Autowired
    public RestTemplate restTemplate;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) 
        List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors = new ArrayList<>();
        clientHttpRequestInterceptors.add(new HttpLoggingInterceptor());
//        clientHttpRequestInterceptors.addAll(restTemplate.getInterceptors());
        restTemplate.setInterceptors(clientHttpRequestInterceptors);
//        restTemplate.setInterceptors(Collections.singletonList(new HttpLoggingInterceptor()));

记录器正在将响应正确地打印到控制台,但最后响应以空的形式返回给调用者。我无法调试并弄清楚。

我发现StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()) 正在读取输入流一次,它不再在其中保存响应主体(现在是空的)

其他人也面临同样的问题,并且有任何想法复制 InputStream 而不从原始 InputStream 中读取它?

【问题讨论】:

InputStream 只能使用一次。因此,除了将 InputStream 数据存储到中间变量并从该数据创建新 InputStream 之外没有其他解决方法(实际上是“复制”) 是的,你是对的,只有使用 ew RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory())) 才能多次读取 HttpInputStream 我已经在下面发布了答案 【参考方案1】:

由于输入流只能被消费一次,并且没有可用于sun.net.www.protocol.http.HttpURLConnection$HttpInputStreamreset()mark(***) 函数。

只有一种方法可以通过以下方式创建 restTemplate 来多次读取响应。

@Bean
public RestTemplate getfxoWsClientRestTemplate()
    RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
    restTemplate.setInterceptors(Collections.singletonList(new HttpLoggingInterceptor()));
    return  restTemplate;

LoggingIntercepter可以这样写

public class HttpLoggingInterceptor implements ClientHttpRequestInterceptor 

    private final static Logger logger = LoggerFactory.getLogger(HttpLoggingInterceptor.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException 
    logger.info("request method: , request URI: , request headers: , request body: ",
            request.getMethod(), request.getURI(), request.getHeaders(), new String(body, Charset.forName("UTF-8")));

    ClientHttpResponse response = execution.execute(request, body);

    logger.info("response status code: , response headers: , response body: ",
            response.getStatusCode(), response.getHeaders(), new String(ByteStreams.toByteArray(response.getBody()), Charset.forName("UTF-8")));

    return response;

【讨论】:

令人惊讶的是,即使拦截器除了调用execution.execute(request, body)之外对请求或响应没有做任何事情,也需要缓冲请求工厂。

以上是关于为啥我的自定义 ClientHttpRequestInterceptor 响应为空的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的自定义 UITableViewCell 没有显示?

为啥我的自定义 cookiejar 不起作用?

为啥我的自定义 UITableViewCell 在 cellForRowAtIndexPath 中为空?

为啥我的自定义 UITableViewcell 没有显示?

为啥我的自定义 ButtonRenderer 不起作用?

为啥我的自定义 Swift 类没有转移到我的 GameScene [关闭]