当前位置: 首页 > 知识库问答 >
问题:

如何使用servlet过滤器记录请求和响应,保留请求正文和响应正文?

寿阳华
2023-03-14

我试图记录应用程序中的每个传入请求和传出响应。我正在使用jee 6,所以我没有ContainerRequestFilter和ContainerResponseFilter类。所以我决定用滤镜。

我用@WebFilter(“/*”)注释了一个类,并实现了Filter接口。我成功地读取了请求头和请求正文。我也很难阅读响应标题和响应正文。下面是代码片段

MyHttpServletResponseWrapper wrapper = new MyHttpServletResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, wrapper);

MyHttpServletResponse seWrapper类

public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {
    private StringWriter sw = new StringWriter();
    public MyHttpServletResponseWrapper(HttpServletResponse response) { super(response); }

    public PrintWriter getWriter() { return new PrintWriter(sw); }

    public ServletOutputStream getOutputStream() {
        return new ServletOutputStream (){
            public void write(int B) { sw.append((char) B); }
        };
    }

    public String getCopy() { sw.toString(); }
}

记录响应后,我将响应写回输出流,以便客户端可以接收响应。下面是代码

logResponse(wrapper);
response.getOutputStream().write(wrapper.getCopy().getBytes());

我不明白的是,阅读后如何将请求正文放回输入流中。

在像Jersey这样的标准API中,有一种使用setEntityInputStream(inputStream)将它放回去的简便方法

如何使用标准的 Java 服务器输出流 API 来做到这一点。

我不是在试图重新发明轮子。我试图避免使用Jersey,以便我的代码可以轻松迁移到新的jee版本。我也想了解像Jersey这样的API是如何做到这一点的。

要阅读正文的响应,我阅读了下面的链接,但它对我不起作用。容器抛出了一个异常,说作者已经获得了。

捕获并记录响应正文

附笔。

我想我想出了如何将输入流设置回去。下面是一些代码

MyRequestWrapper requestwrapper = new MyRequestWrapper((HttpServletRequest) request);

chain.doFilter;

我的请求包装器类

public class MyRequestWrapper extends HttpServletRequestWrapper {
    String body; 
    int counter;
    public MyRequestWrapper(HttpServletRequest request) { super(request); }

    public void setBody(String body) { this.body = body;}

    public ServletInputStream getInputStream() {
        return new ServletInputStream() {
            public interest read() throws IOException {
                if(counter >=body.length()) return -1;
                return body.charAt(counter++);
            }
        };
    }
}

我知道被重写的getInputStream和getOutputStream中的代码质量都不怎么样。现在我不担心这个。我想知道这是不是一个正确的想法?如果是这样的话,我想专注于代码质量。

共有1个答案

勾长卿
2023-03-14
/** I know its too late but it can be helpfull for others as well. **//
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

public class ApiIOLoggerFilter implements Filter {
@Override 
public void init(FilterConfig filterConfig) {}
@Override 
public void destroy() {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper((HttpServletResponse) response);
        try {
            chain.doFilter(requestWrapper, responseWrapper);
        } finally {
            performRequestAudit(requestWrapper);
            performResponseAudit(responseWrapper);
        }
    } else {
        chain.doFilter(request, response);
    }
}

private void performRequestAudit(ContentCachingRequestWrapper requestWrapper) {
    if (requestWrapper != null && requestWrapper.getContentAsByteArray() != null && requestWrapper.getContentAsByteArray().length > 0) {
        logger.info("\n Headers:: {} \n Request Body:: {}", new ServletServerHttpRequest((HttpServletRequest)requestWrapper.getRequest()).getHeaders(),
                getPayLoadFromByteArray(requestWrapper.getContentAsByteArray(), requestWrapper.getCharacterEncoding()));
    }
}

private void performResponseAudit(ContentCachingResponseWrapper responseWrapper)
        throws IOException {
    if (responseWrapper != null && responseWrapper.getContentAsByteArray() != null
            && responseWrapper.getContentAsByteArray().length > 0) {
        logger.info("Response Body:: {}", getPayLoadFromByteArray(responseWrapper.getContentAsByteArray(),
                responseWrapper.getCharacterEncoding()));
    } else {
        performErrorResponseAudit(responseWrapper);
    }
    responseWrapper.copyBodyToResponse();
}

private void performErrorResponseAudit(ContentCachingResponseWrapper responseWrapper) {
    logger.warn("HTTP Error Status Code::" + responseWrapper.getStatus());
}

private String getPayLoadFromByteArray(byte[] requestBuffer, String charEncoding) {
    String payLoad = "";
    try {
        payLoad = new String(requestBuffer, charEncoding);
    } catch (UnsupportedEncodingException unex) {
        payLoad = "Unsupported-Encoding";
    }
    return payLoad;
}

}
 类似资料:
  • 我在改型API中找不到记录完整请求/响应体的相关方法。我希望在探查器中得到一些帮助(但它只提供关于响应的元数据)。我尝试在构建器中设置日志级别,但这也没有帮助: 编辑:此代码正在工作。我不知道为什么它在早些时候不起作用。可能是因为我用的是旧版本的改装。

  • 我有一个spring应用程序,它可以与Mobile交换JSON。Spring控制器如下所示: 我想知道,记录http请求正文和响应正文的最佳方式是什么?目前,我有一个定制的json消息转换器,它在从json中创建bean之前记录一个请求正文。我使用CustomTraceInterceptor记录响应正文。不幸的是,CustomTraceInterceptor不允许记录请求正文。 任何更好的解决方案

  • 在Jersey中,可以添加或 两者都是使用PackagesResourceConfig添加的: 谢谢

  • 问题内容: 我想记录一个axis2客户端发出的所有请求/响应。我试图在http://code.google.com/support/bin/answer.py?hl=zh_CN&answer=15137中创建一个称为describer 的文件,但没有成功(我没有日志文件)。 请求是通过https发出的,我不确定是否重要。我试过了 和 没有成功。 问题答案: 对于SOAP消息的Axis2客户端日志记

  • 因此,我试图使用wiremck向带有请求正文的URL发出后请求,然后使用我的respons.json文件返回响应。(自定义响应) 我就是这样设置的,但我似乎找不到任何关于如何设置带有请求主体的post存根(包含数据,比如说尝试创建ID),然后检索自定义响应主体(从json文件创建ID响应)的信息。我该怎么设置呢。我尝试通过json文件请求生成id,然后尝试检索创建的id。 WithBodyFile

  • 我正在尝试将API请求负载和响应数据记录到Azure Application Insight。使用跟踪我可以记录。但是我想知道什么是将请求和响应数据记录到application Insight的最佳方法。因为数据是巨大的,所以API调用的数量会更多。我不能仅仅使用跟踪来跟踪数十万个请求和响应数据。我尝试了一些博客,比如使用itelemetryinitializer/httpcontext.feat