Получить тело запроса в картографе исключений - PullRequest
15 голосов
/ 11 ноября 2011

Я пытаюсь получить тело запроса в 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());

    }

}

Так что моя дилемма в том, что я не могу получить тело запроса на регистрацию, потому что API сервлета не позволит вам вызывать request.getInputStream () / request.getReader () более одного раза для запроса (и JAX-RS явно вызывая его для разбора запроса). Кто-нибудь знает, есть ли способ сделать то, что я пытаюсь сделать?

Ответы [ 2 ]

11 голосов
/ 23 сентября 2013

Этот вопрос немного старше, но все же ответ может помочь другим.Мой пример также зависит от 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);
    }

}

И использовать @Inject с javax.inject.Providerв вашем ExceptionMapper для получения инъекции 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 достаточно.

0 голосов
/ 04 мая 2013

Одно из возможных решений - использовать фильтр сервлетов и обернуть запрос, который позволяет перехватывать вызовы чтения для потока ввода запроса. Пример псевдокода (зависит от 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();
    }
}

Фильтр:

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, и вы можете найти пример реализации здесь: Изменить тело HttpServletRequest

...