How to use Jersey interceptors to get request body

痞子三分冷 提交于 2019-12-18 05:37:21

问题


I am using REST-Jersey in my project. All the POST data is send in JSON format and unmarshalled at server-side into respective beans. Something like this:

Sending request to server:

    $('a#sayHelloPost').click(function(event){
        event.preventDefault();
        var mangaData = {
            title:'Bleach',
            author:'Kubo Tite'
        }
        var formData=JSON.stringify(mangaData);
        console.log(formData);
        $.ajax({
                url:'rest/cred/sayposthello',
                type: 'POST',
                data: formData,
                dataType: 'json',
                contentType:'application/json'
        })
});

Payload:

{"title":"Bleach","author":"Kubo Tite"}

Server-end:

@POST
@Path("/sayposthello")
@Produces(MediaType.APPLICATION_JSON)
public Response sayPostHello(MangaBean mb){
    System.out.println(mb);
    return Response.status(200).build();
}

MangaBean:

public class MangaBean {
    private String title;
    private String author;
    @Override
    public String toString() {
        return "MangaBean [title=" + title + ", author=" + author + "]";
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
}

Output on console:

MangaBean [title=Bleach, author=Kubo Tite]

I got the REST-interceptor implementation from here.

public class JerseyFilter implements ContainerRequestFilter{

    @Override
    public ContainerRequest filter(ContainerRequest req) {
        return req;
    }

} 

I want to access the payload(request body) in the interceptor. As the data is in JSON format, its not accessible as request parameters. Is there a way I can get the request body in the interceptor method? Please advice.


回答1:


Here is one way you can implement, very similar to how Jersey implements its logging filters. You can read the entity and stick it back to the request, so you accidentally do not consume it in your filter.

import com.sun.jersey.api.container.ContainerException;
import com.sun.jersey.core.util.ReaderWriter;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class JerseyFilter implements ContainerRequestFilter {

    @Override
    public ContainerRequest filter(ContainerRequest request) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        InputStream in = request.getEntityInputStream();
        final StringBuilder b = new StringBuilder();
        try {
            if (in.available() > 0) {
                ReaderWriter.writeTo(in, out);

                byte[] requestEntity = out.toByteArray();
                printEntity(b, requestEntity);

                request.setEntityInputStream(new ByteArrayInputStream(requestEntity));
            }
            return request;
        } catch (IOException ex) {
            throw new ContainerException(ex);
        }

    }

    private void printEntity(StringBuilder b, byte[] entity) throws IOException {
        if (entity.length == 0)
            return;
        b.append(new String(entity)).append("\n");
        System.out.println("#### Intercepted Entity ####");
        System.out.println(b.toString());
    }
}



回答2:


You can get the POST Body from the Requests Input Stream. Try something like this:

        @Override
        public ContainerRequest filter(ContainerRequest req) {
            try{

            StringWriter writer = new StringWriter();       
                IOUtils.copy(req.getEntityInputStream(), writer, "UTF-8");

            //This is your POST Body as String      
            String body = writer.toString();

                }
            catch (IOException e) {}
         return req; }



回答3:


You can only read the content once, because it's an input stream. If you pick it up in the interceptor then you won't be able to provide it in the main parsing.

What you need to do is to create a filter which reads the data and makes it available to anyone else who needs it. Basic steps are:

  • in your filter create a new subclass of HttpServletRequestWrapper which reads the input in to a buffer and overrides getInputStream() to provide a new input stream to that buffer
  • pass your new subclass down the chain



回答4:


Do not use in.available() method to check the total bytes of Inputstream. Some clients does not set this value. And in this case it will be foul eventhough the message body input stream exists.

 InputStream in = request.getEntityInputStream();
        final StringBuilder b = new StringBuilder();
        try {
            if (in.available() > 0)

Use below code

String json = IOUtils.toString(requestContext.getEntityStream(), Charsets.UTF_8);
            messageBody = json;
            InputStream in = IOUtils.toInputStream(json);
            requestContext.setEntityStream(in);


来源:https://stackoverflow.com/questions/14560276/how-to-use-jersey-interceptors-to-get-request-body

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!