在异常映射器中检索请求正文

发布于 2024-12-15 03:57:40 字数 599 浏览 1 评论 0原文

我正在尝试在 JAX-RS ExceptionMapper 中检索请求的正文。到目前为止,这是我的代码:

@Provider @Componenet
public class BaseExceptionMapper implements ExceptionMapper<Exception> {

    @Context private HttpServletRequest request;

    @Override
    public Response toResponse(Exception ex) {

        // Trying to retrieve request body for logging throws an error
        String requestBody = IOUtils.toString(request.getInputStream());

    }

}

所以我的困境是我无法获取用于记录的请求正文,因为 servlet API 不允许您多次调用 request.getInputStream() / request.getReader() 来请求(和 JAX -RS 显然是调用它来解析请求)。有谁知道是否有办法做我想做的事情?

I'm trying to retrieve the body of a request in a JAX-RS ExceptionMapper. Here is my code so far:

@Provider @Componenet
public class BaseExceptionMapper implements ExceptionMapper<Exception> {

    @Context private HttpServletRequest request;

    @Override
    public Response toResponse(Exception ex) {

        // Trying to retrieve request body for logging throws an error
        String requestBody = IOUtils.toString(request.getInputStream());

    }

}

So my dilemma is I can't get the request body for logging because the servlet API wont allow you to call request.getInputStream() / request.getReader() more than once for a request (and JAX-RS Is obviously calling it to parse the request). Does anyone know if there is a way to do what I'm trying to do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

江城子 2024-12-22 03:57:40

这个问题有点老了,但答案仍然可能对其他人有帮助。我的示例还依赖于 Commons-Io。

您可以创建一个ContainerRequestFilter并使用TeeInputStream来代理/复制原始InputStream:

@Provider
@Priority(Priorities.ENTITY_CODER)
public class CustomRequestWrapperFilter implements ContainerRequestFilter { 

    @Override
    public void filter(ContainerRequestContext requestContext)
            throws IOException {
        ByteArrayOutputStream proxyOutputStream = new ByteArrayOutputStream();
        requestContext.setEntityStream(new TeeInputStream(requestContext.getEntityStream(), proxyOutputStream));
        requestContext.setProperty("ENTITY_STREAM_COPY", proxyOutputStream);
    }

}

并在ExceptionMapper中使用@Inject和javax.inject.Provider来注入ContainerRequest。

ExceptionMapper 看起来像这样:

@Provider
public class BaseExceptionMapper implements ExceptionMapper<Exception> {

    @Inject
    private javax.inject.Provider<ContainerRequest> containerRequestProvider;

    @Override
    public Response toResponse(Exception exception) {
        ByteArrayOutputStream bos = (ByteArrayOutputStream) containerRequestProvider
                .get().getProperty("ENTITY_STREAM_COPY");
        String requestBody = bos.toString();
        ...
    }

}

当我也使用 @Component 注释时,我的 ExceptionMapper 没有被使用。我认为@Provider 就足够了。

This question is a bit older, but still the answer may help others. My Example also depends on Commons-Io.

You can create a ContainerRequestFilter and use TeeInputStream to proxy/copy the original InputStream:

@Provider
@Priority(Priorities.ENTITY_CODER)
public class CustomRequestWrapperFilter implements ContainerRequestFilter { 

    @Override
    public void filter(ContainerRequestContext requestContext)
            throws IOException {
        ByteArrayOutputStream proxyOutputStream = new ByteArrayOutputStream();
        requestContext.setEntityStream(new TeeInputStream(requestContext.getEntityStream(), proxyOutputStream));
        requestContext.setProperty("ENTITY_STREAM_COPY", proxyOutputStream);
    }

}

And use @Inject with javax.inject.Provider in your ExceptionMapper to get the ContainerRequest injected.

The ExceptionMapper would look like this:

@Provider
public class BaseExceptionMapper implements ExceptionMapper<Exception> {

    @Inject
    private javax.inject.Provider<ContainerRequest> containerRequestProvider;

    @Override
    public Response toResponse(Exception exception) {
        ByteArrayOutputStream bos = (ByteArrayOutputStream) containerRequestProvider
                .get().getProperty("ENTITY_STREAM_COPY");
        String requestBody = bos.toString();
        ...
    }

}

When I have also used the @Component annotation my ExceptionMapper was not used. I think that @Provider is sufficient.

梦冥 2024-12-22 03:57:40

一种可能的解决方案是使用 servlet 过滤器并包装请求,这允许您拦截对请求输入流的读取调用。示例伪代码(取决于 commons-io):

import org.apache.commons.io.output.StringBuilderWriter;
import org.apache.commons.io.input.TeeInputStream;
class MyHttpRequest extends HttpServletRequestWrapper {
    private StringBuilderWriter myString = new StringBuilderWriter();
    private InputStream myIn;
    public MyHttpRequest(HttpServletRequest request) {
        super(request);
        myIn = new TeeInputStream(request.getInputStream(), myString);
    }
    @Override public ServletInputStream getInputStream()
            throws java.io.IOException {
        // this will need an extra wrapper to compile
        return myIn;
    }
    public String getRequestBody() {
        return myString.toString();
    }
}

Filter:

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    MyHttpRequest wrapper = new MyHttpRequest((HttpServletRequest) request);
    chain.doFilter(wrapper, response, chain);
}

Mapper:

@Context private HttpServletRequest request;
@Override public Response toResponse(Exception ex) {
    String body = "";
    if (this.request instanceof MyHttpRequest) {
        body = ((MyHttpRequest)request).getRequestBody()
    }
}

您需要一个 ServletInputStream 的包装类,您可以在此处找到示例实现:< a href="https://stackoverflow.com/questions/681263/modify-httpservletrequest-body">修改 HttpServletRequest 正文

One possible solution is to use a servlet filter and wrap the request, which allows you to intercept read calls to the request input stream. Example pseudo-code (depends on commons-io):

import org.apache.commons.io.output.StringBuilderWriter;
import org.apache.commons.io.input.TeeInputStream;
class MyHttpRequest extends HttpServletRequestWrapper {
    private StringBuilderWriter myString = new StringBuilderWriter();
    private InputStream myIn;
    public MyHttpRequest(HttpServletRequest request) {
        super(request);
        myIn = new TeeInputStream(request.getInputStream(), myString);
    }
    @Override public ServletInputStream getInputStream()
            throws java.io.IOException {
        // this will need an extra wrapper to compile
        return myIn;
    }
    public String getRequestBody() {
        return myString.toString();
    }
}

Filter:

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    MyHttpRequest wrapper = new MyHttpRequest((HttpServletRequest) request);
    chain.doFilter(wrapper, response, chain);
}

Mapper:

@Context private HttpServletRequest request;
@Override public Response toResponse(Exception ex) {
    String body = "";
    if (this.request instanceof MyHttpRequest) {
        body = ((MyHttpRequest)request).getRequestBody()
    }
}

You'll need a wrapper class for ServletInputStream, and you can find an example implementation here: Modify HttpServletRequest body

柳若烟 2024-12-22 03:57:40

我知道这是一个老问题,但我找到了一个我认为很高兴分享的解决方法。

通过以下代码,您应该能够在 ExceptionMapper 中获取 ContainerRequestContext ,然后您可以读取正文、查询参数、标头等。

@Provider
public class CustomExceptionMapper implements ExceptionMapper<CustomException> {

    @Context
    private ResourceContext resourceContext;

    @Override
    public Response toResponse(CustomException e) {
        ContainerRequestContext requestContext =
                resourceContext.getResource(ContainerRequestContext.class);
    }

}

希望它能有所帮助

I know this is an old question but I found a workaround that I think it's nice to share.

With the following code you should be able to get the ContainerRequestContext inside the ExceptionMapper, then you can read the body, query params, headers, etc.

@Provider
public class CustomExceptionMapper implements ExceptionMapper<CustomException> {

    @Context
    private ResourceContext resourceContext;

    @Override
    public Response toResponse(CustomException e) {
        ContainerRequestContext requestContext =
                resourceContext.getResource(ContainerRequestContext.class);
    }

}

Hope it can help

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文