Dumping bad requests

2019-08-29 01:50发布

问题:

I have a service implemented with Dropwizard and I need to dump incorrect requests somewhere.

I saw that there is a possibility to customise the error message by registering ExceptionMapper<JerseyViolationException>. But I need to have the complete request (headers, body) and not only ConstraintViolations.

回答1:

You can inject ContainerRequest into the ExceptionMapper. You need to inject it as a javax.inject.Provider though, so that you can lazily retrieve it. Otherwise you will run into scoping problems.

@Provider
public class Mapper implements ExceptionMapper<ConstraintViolationException> {

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

    @Override
    public Response toResponse(ConstraintViolationException ex) {
        ContainerRequest request = requestProvider.get();
    }
}

In the ContainerRequest, you can get headers with getHeaderString() or getHeaders(). If you want to get the body, you need to do a little hack because the entity stream is already read by Jersey by the time the mapper is reached. So we need to implement a ContainerRequestFilter to buffer the entity.

public class EntityBufferingFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext containerRequestContext) throws IOException {
        ContainerRequest request = (ContainerRequest) containerRequestContext;
        request.bufferEntity();
    }
}

You might not want this filter to be called for all requests (for performance reasons), so you might want to use a DynamicFeature to register the filter just on methods that use bean validation (or use Name Binding).

Once you have this filter registered, you can read the body using ContainerRequest#readEntity(Class). You use this method just like you would on the client side with Response#readEntity(). So for the class, if you want to keep it generic, you can use String.class or InputStream.class and convert the InputStream to a String.

ContainerRequest request = requestProvider.get();
String body = request.readEntity(String.class);