How to retrieve raw post data from HttpServletRequ

2019-01-13 01:09发布

问题:

I'm trying to get the post data in Java. Seems like it should be one of the simplest things to do right? I mean, HttpServletRequest.getParameter has to do it right? So how can you get the raw post data?

I found HttpServletRequest get JSON POST data and used Kdeveloper's code to pull the post data from a request. It works, but theres a catch: I can only get that post data once.

Heres the method I made from Kdeveloper's code:

public static String getPostData(HttpServletRequest req) {
    StringBuilder sb = new StringBuilder();
    try {
        BufferedReader reader = req.getReader();
        reader.mark(10000);

        String line;
        do {
            line = reader.readLine();
            sb.append(line).append("\n");
        } while (line != null);
        reader.reset();
        // do NOT close the reader here, or you won't be able to get the post data twice
    } catch(IOException e) {
        logger.warn("getPostData couldn't.. get the post data", e);  // This has happened if the request's reader is closed    
    }

    return sb.toString();
}

Previously I had closed the reader at the end of this method, but that caused exceptions when the method ran more than once on the same request. Without closing it, no exceptions happen, but the method returns an empty string.

Honestly, there should just be an exposed req.getPostData() method - did no one think that would be useful?

So how can I write this method such that it always returns the correct post data?

回答1:

The request body is available by HttpServletRequest#getInputStream() and #getReader().

InputStream body = request.getInputStream();
// ...

Note that you can read it only once. The client ain't going to resend it multiple times. Calling getParameter() and so on will implicitly also read it. You've got to store the body somewhere and process yourself.



回答2:

We had a situation where IE forced us to post as text/plain, so we had to manually parse the parameters using getReader. The servlet was being used for long polling, so when AsyncContext::dispatch was executed after a delay, it was literally reposting the request empty handed.

So I just stored the post in the request when it first appeared by using HttpServletRequest::setAttribute. The getReader method empties the buffer, where getParameter empties the buffer too but stores the parameters automagically.

    String input = null;

    // we have to store the string, which can only be read one time, because when the
    // servlet awakens an AsyncContext, it reposts the request and returns here empty handed
    if ((input = (String) request.getAttribute("com.xp.input")) == null) {
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader = request.getReader();

        String line;
        while((line = reader.readLine()) != null){
            buffer.append(line);
        }
        // reqBytes = buffer.toString().getBytes();

        input = buffer.toString();
        request.setAttribute("com.xp.input", input);
    }

    if (input == null) {
        response.setContentType("text/plain");
        PrintWriter out = response.getWriter();
        out.print("{\"act\":\"fail\",\"msg\":\"invalid\"}");
    }