如何在NestJS中通过NestInterceptor在响应发送给客户端前记录响应数据
问题

目前我只能检查Request对象,无法查看Controller发送的Response对象。
我可以从Response中获取以下属性:
- statusCode
- statusMessage
等等
如何在响应发送给客户端前追踪响应体?
解决方案
要在响应发送给客户端前追踪响应体,核心思路是包装Response对象,通过自定义响应包装器捕获输出流中的内容,下面以Spring MVC为例给出具体实现:
1. 自定义响应包装器类
继承HttpServletResponseWrapper,重写输出流相关方法,将响应内容暂存到字节数组中:
public class ResponseWrapper extends HttpServletResponseWrapper { private final ByteArrayOutputStream byteArrayOutputStream; private ServletOutputStream servletOutputStream; private PrintWriter printWriter; public ResponseWrapper(HttpServletResponse response) throws IOException { super(response); byteArrayOutputStream = new ByteArrayOutputStream(); } @Override public ServletOutputStream getOutputStream() throws IOException { if (servletOutputStream == null) { servletOutputStream = new DelegatingServletOutputStream(byteArrayOutputStream); } return servletOutputStream; } @Override public PrintWriter getWriter() throws IOException { if (printWriter == null) { printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream, getCharacterEncoding())); } return printWriter; } @Override public void flushBuffer() throws IOException { if (servletOutputStream != null) { servletOutputStream.flush(); } if (printWriter != null) { printWriter.flush(); } super.flushBuffer(); } // 获取捕获到的响应体字符串 public String getResponseBody() throws IOException { flushBuffer(); return byteArrayOutputStream.toString(getCharacterEncoding()); } }
2. 自定义过滤器拦截请求
创建过滤器替换原生Response为自定义包装器,在响应处理完成后读取并处理响应体:
@Component public class ResponseLoggingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response); // 继续执行请求链,Controller会将响应写入包装器 chain.doFilter(request, responseWrapper); // 此处获取响应体,可根据需求打印、存储或分析 String responseBody = responseWrapper.getResponseBody(); System.out.println("捕获到的响应体:" + responseBody); // 将暂存的响应内容写回原生响应,确保客户端能正常接收 ServletOutputStream outputStream = response.getOutputStream(); outputStream.write(responseBody.getBytes(responseWrapper.getCharacterEncoding())); outputStream.flush(); } }
3. 注册过滤器(按需配置)
若未通过@Component自动注册,可通过配置类手动注册并指定拦截路径:
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean<ResponseLoggingFilter> responseLoggingFilterRegistration() { FilterRegistrationBean<ResponseLoggingFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new ResponseLoggingFilter()); registrationBean.addUrlPatterns("/*"); // 拦截所有请求路径 return registrationBean; } }
如果是其他Web框架(如纯Servlet、Spring Boot等),核心逻辑一致:通过包装响应对象捕获输出流,在响应提交前读取内容,再将内容写回原响应保证客户端正常接收。
内容的提问来源于stack exchange,提问作者Rohit Sengar
相关产品推荐
相关产品推荐

