背景: 作为 API 请求周期的一部分,例如,对于 OTP 验证,我们调用外部 API (xxxx.com),如果 OTP 无效,则返回 401,同时带有 JSON 响应。
我们使用 Spring 的 RestTemplate 对 xxxx.com 进行外部调用,我们希望将 401 响应捕获为 Java 对象,但我们未能做到这一点。我们看到回复已被编辑。
我们使用的 RestTemplate 来自 JAR
org.springframework:spring-web:6.1.5
拨打电话的线路:
this.restTemplate.exchange("https://xxxx.com", HttpMethod.PUT, entity, responseType);
我们如何捕获非 2XX:
catch (HttpClientErrorException e) {
if (successfulHttpStatuses.contains(e.getStatusCode())) {
return e.getResponseBodyAs(responseType);
} else {
log.error("{} returned a {} status - {}", clientName, e.getStatusCode(), e.getMessage());
throw e;
}
我们的客户端完美适用于 2XX,只是在 401 期间,我们得到日志,
XXXClient returned a 401 status - [no body]
正如我们所期望的那样,“有一个身体”。 请看这个:
此外,我们提到的外部 xxxx.com 使用承载身份验证,并针对无效的 JWT 抛出 401。
所以,我相信这是一个经过深思熟虑的设计决定,出于安全原因屏蔽 401 响应。对于这种情况有解决办法吗?
@Test
public void unauthorizedRequestWithBodyTest() {
this.server
.expect(ExpectedCount.once(), requestTo("/unauthorized"))
.andExpect(method(HttpMethod.PUT))
.andRespond(withStatus(HttpStatus.UNAUTHORIZED).body(
" { \"message\" : \"Something is broken\", \"status\": \"401\" } "));
try {
restTemplate.exchange("unauthorized", HttpMethod.PUT, null, String.class);
} catch (HttpClientErrorException e) {
System.out.println("Response with body content:");
System.out.printf("%s returned a %s status - %s\n\n", "clientName", e.getStatusCode(), e.getResponseBodyAsString());
}
}
@Test
public void unauthorizedRequestWithoutBodyTest() {
this.server
.expect(ExpectedCount.once(), requestTo("/unauthorized"))
.andExpect(method(HttpMethod.PUT))
.andRespond(withStatus(HttpStatus.UNAUTHORIZED));
try {
restTemplate.exchange("unauthorized", HttpMethod.PUT, null, String.class);
} catch (HttpClientErrorException e) {
System.out.println("Response without body content:");
System.out.printf("%s returned a %s status - %s\n", "clientName", e.getStatusCode(), e.getMessage());
System.out.printf("%s returned a %s status - %s\n\n", "clientName", e.getStatusCode(), e.getResponseBodyAsString());
}
}
输出如下:
Response with body content:
clientName returned a 401 UNAUTHORIZED status - { "message" : "Something is broken", "status": "401" }
Response without body content:
clientName returned a 401 UNAUTHORIZED status - 401 Unauthorized: [no body]
clientName returned a 401 UNAUTHORIZED status -
从实现中您可以看到,当responseBody为空时,
getErrorMessage()
方法返回
[no body]
文本if (ObjectUtils.isEmpty(responseBody)) {
return preface + "[no body]";
}
org.springframework.web.client.DefaultResponseErrorHandler#getErrorMessage