• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

使用RestTemplate,显示请求信息,响应信息

互联网 diligentman 2个月前 (12-01) 19次浏览

使用RestTemplate,显示请求信息,响应信息

这里不讲怎么用RestTemplate具体细节用法,就是一个学习中的过程记录

一个简单的例子

public class App { public static void main(String[] args) {  String url = "https://api.uixsj.cn/hitokoto/get";  RestTemplate restTemplate = new RestTemplate();  String body = restTemplate.getForObject(url, String.class);  System.out.println(body); }}

运行结果:

使用RestTemplate,显示请求信息,响应信息

❓:现在我想看看他的请求头,请求参数,响应头,响应体的详细信息是怎么样子的,这样也方便以后检查请求参数是否完整,响应正确与否。

经过搜集资料发现ClientHttpRequestInterceptor满足需求,于是就有了下面的代码

打印请求头/响应头

public class App { public static void main(String[] args) {  String url = "https://api.uixsj.cn/hitokoto/get";  RestTemplate restTemplate = new RestTemplate();  // 加上拦截器打印将请求请求,响应信息打印出来  restTemplate.setInterceptors(Collections.singletonList(new LoggingInterceptor()));  String body = restTemplate.getForObject(url, String.class);  System.out.println(body); }}@Slf4jclass LoggingInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {  displayRequest(request, body);  ClientHttpResponse response = execution.execute(request, body);  displayResponse(response);  return response; } /**  * 显示请求相关信息  * @param request  * @param body  */ private void displayRequest(HttpRequest request, byte[] body) {  log.debug("====request info====");  log.debug("URI   : {}", request.getURI());  log.debug("Method  : {}", request.getMethod());  log.debug("Req Headers : {}", this.headersToString(request.getHeaders()));  log.debug("Request body: {}", body == null ? "" : new String(body, StandardCharsets.UTF_8)); } /**  * 显示响应相关信息  * @param response  * @throws IOException  */ private void displayResponse(ClientHttpResponse response) throws IOException {  StringBuilder inputStringBuilder = new StringBuilder();  try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), StandardCharsets.UTF_8))) {   String line = bufferedReader.readLine();   while (line != null) {    inputStringBuilder.append(line);    inputStringBuilder.append('n');    line = bufferedReader.readLine();   }  }  log.debug("====response info====");  log.debug("Status code : {}", response.getStatusCode());  log.debug("Status text : {}", response.getStatusText());  log.debug("Resp Headers : {}", headersToString(response.getHeaders()));  log.debug("Response body: {}", inputStringBuilder.toString()); } /**  * 将Http头信息格式化处理  * @param httpHeaders  * @return  */ private String headersToString(HttpHeaders httpHeaders) {  if (Objects.isNull(httpHeaders)) {   return "[]";  }  return httpHeaders.entrySet().stream()    .map(entry -> {     List<String> values = entry.getValue();     return "t" + entry.getKey() + ":" + (values.size() == 1 ?       """ + values.get(0) + """ :       values.stream().map(s -> """ + s + """).collect(Collectors.joining(", ")));    })    .collect(Collectors.joining(", n", "n[n", "n]n")); }}

运行结果:

使用RestTemplate,显示请求信息,响应信息

执行过程中会报错,具体错误信息是

Exception in thread "main" org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://api.uixsj.cn/hitokoto/get": stream is closed; nested exception is java.io.IOException: stream is closed

这里报错信息是流已关闭,报错是在添加LoggingInterceptor后出现的,那就是新加代码引起的。在看看LoggingInterceptor的实现,什么地方操作了流,并且关闭了流。

LoggingInterceptor.displayResponse这个方法里面,为了读取响应体操作了流response.getBody()

try (...) {}// 这个try块结束后就把流给关了

注释掉代码中流操作相关代码,再次运行没有错误信息。因该是在拦截器后,RestTemplate也需要操作了response.getBody()的流(废话)。

Response body 不能读第二次这个很要命呀

问题找到了,初步的想到了几种解决

  1. 改写代码,不close流,读取完之后再reset
  2. 代理一下ClientHttpResponse每次调用getBody都返回一个新的输入流

解决不能重复读Response body

方法一:读取完后不关闭流

// 略...InputStream responseBody = response.getBody();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseBody, StandardCharsets.UTF_8));String line = bufferedReader.readLine();while (line != null) { inputStringBuilder.append(line); inputStringBuilder.append('n'); line = bufferedReader.readLine();}responseBody.reset();// 略...

很遗憾,执行后依旧有错误

Exception in thread "main" org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://api.uixsj.cn/hitokoto/get": mark/reset not supported; nested exception is java.io.IOException: mark/reset not supported

说的很清楚,不支持mark/reset方法。很明显了它不允许随意修改读取定位。没办法只转为第二种方法了。

方法二:代理,每次都返回一个新的流

  1. 静态代理实现ClientHttpResponse接口,好在ClientHttpResponse实现的接口数量不多,实现的代码如下。
@Slf4jclass LoggingInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[].........

喜欢 (0)