java - 如何访问 Spring Boot 默认错误响应的 HTTP 响应内容?
问题描述
我有一个 Spring Boot 应用程序,它正在捕获对应用程序发出的 REST 请求的 HTTP 响应内容。我这样做是为了记录和将来分析进入系统的请求。
目前,我将其实现为过滤器 bean (per OncePerRequestFilter
),使用 aContentCachingResponseWrapper
来捕获写入输出流的内容:
@Component
public class ResponseBodyLoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
ContentCachingResponseWrapper cachingResponse =
new ContentCachingResponseWrapper(response);
try {
filterChain.doFilter(request, cachingResponse);
} finally {
byte[] responseBytes = cachingResponse.getContentInputStream().readAllBytes();
System.out.println("Response: \"" + new String(responseBytes) + "\"");
cachingResponse.copyBodyToResponse();
}
}
}
这适用于对应用程序的大多数请求。但是,它没有捕获的一件事是默认的 Spring Boot 错误响应。它不是捕获响应的内容,而是返回空字符串。
build.gradle
plugins {
id 'org.springframework.boot' version '2.5.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
控制器:
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/404")
public void throw404() {
throw new ResponseStatusException(BAD_REQUEST);
}
}
HTTP 响应:
{
"timestamp": "2021-08-03T18:30:18.934+00:00",
"status": 400,
"error": "Bad Request",
"path": "/test/404"
}
系统输出:
Response: ""
我已经确认,如果我从嵌入式 Tomcat 的 Spring Boot 默认切换到嵌入式 Jetty(使用spring-boot-starter-jetty
和排除spring-boot-starter-tomcat
),仍然会出现此问题。
如何在我的应用程序中捕获 Spring Boot 错误响应输出?请注意,如果另一个解决方案解决了问题,我不需要它作为过滤器。
解决方案
我还没有确定一个好方法来实现在过滤器中获取 Spring Boot 错误响应主体的既定目标,但是经过一些调试和深入了解 Spring 内部,我相信我可能已经确定它为什么不起作用,至少。
它看起来像是BasicErrorController.error(HttpServletRequest request)
框架的一部分,负责返回要呈现的错误对象。
但是,观察调用此控制器方法的位置,它看起来好像是在Servlet.service()
实际过滤发生之后的调用期间发生的。每人:tomcat-embed-core
_ApplicationFilterChain
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
// [...]
Filter filter = filterConfig.getFilter();
// [...]
filter.doFilter(request, response, this);
// [...]
// We fell off the end of the chain -- call the servlet instance
// [...]
servlet.service(request, response);
// [...]
}
根据上面的代码,ResponseBodyLoggingFilter
过滤器在 中被调用filter.doFilter(request, response, this)
,但BasicErrorController.error(...)
直到之后才被调用servlet.service(request, response)
。
推荐阅读
- python - 在 python 中将数据分类到 bin 中的有效方法
- mysql - 在 NiFi 中将 CSV 数据摄取到 MySQL DB
- python - 熊猫日期未显示在情节上
- python - pandas.DataFrame.shift 函数的问题
- api - Google OAuth 同意屏幕未显示范围选项
- bash - 是否可以在 bash 中创建复合别名?
- ios - 如何在手表应用程序上访问 PFUser.Current()
- javascript - 如何为单页应用程序重新排列 div
- python - Python gTTS 说话剪贴板
- three.js - 如何有效地旋转 IBL 管道中使用的环境贴图?