Nhận phần thân yêu cầu POST từ HttpServletRequest


115

Tôi đang cố gắng lấy toàn bộ phần nội dung từ đối tượng HttpServletRequest.

Mã tôi đang theo dõi trông giống như sau:

if ( request.getMethod().equals("POST") )
{
    StringBuffer sb = new StringBuffer();
    BufferedReader bufferedReader = null;
    String content = "";

    try {
        //InputStream inputStream = request.getInputStream();
        //inputStream.available();
        //if (inputStream != null) {
        bufferedReader =  request.getReader() ; //new BufferedReader(new InputStreamReader(inputStream));
        char[] charBuffer = new char[128];
        int bytesRead;
        while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 ) {
            sb.append(charBuffer, 0, bytesRead);
        }
        //} else {
        //        sb.append("");
        //}

    } catch (IOException ex) {
        throw ex;
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                throw ex;
            }
        }
    }

    test = sb.toString();
}

và tôi đang thử nghiệm chức năng với curl và wget như sau:

curl --header "MD5: abcd" -F "fileupload=@filename.txt http://localhost:8080/abcd.html"

wget --header="MD5: abcd" --post-data='{"imei":"351553012623446","hni":"310150","wdp":false}' http://localhost:8080/abcd.html"

Nhưng while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 )nó không trả về bất cứ điều gì, và vì vậy tôi không nhận được gì trên StringBuffer.

Câu trả lời:


192

Trong Java 8, bạn có thể làm điều đó một cách đơn giản và gọn gàng:

if ("POST".equalsIgnoreCase(request.getMethod())) 
{
   test = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
}

8
Tôi thích giải pháp này hơn vì nó là một Java thuần túy mà không có bất kỳ sự phụ thuộc nào của bên thứ ba.
lu_ko,

49
Mặc dù hãy nhớ rằng chúng ta không thể đọc lại phần thân yêu cầu như getReaderđã được gọi.
Nikhil Sahu

1
Làm cách nào để chúng tôi có thể thiết lập lại dữ liệu HTTP POST mới được định dạng trở lại thành yêu cầu?
Pra_A

1
Tôi đã thử giải pháp này nhưng nó đưa ra một vấn đề rất nghiêm trọng, tôi đã sử dụng mã này để ghi thông tin yêu cầu bên trong bộ lọc OncePerRequest và khi tôi sử dụng nó, tất cả ràng buộc @modelAttribute của tôi trong tất cả các phương thức đăng bài của tôi đều cho giá trị rỗng trong tất cả các trường của một đối tượng. Tôi không khuyên bạn nên sử dụng cách tiếp cận này.
Mohammed Fathi

Chúng ta không nên đóng đầu đọc?
Aristo_sh

46

Cách dễ dàng với commons-io.

IOUtils.toString(request.getReader());

https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/IOUtils.html


Tôi muốn giúp đỡ nếu bạn có thể đưa ra một ví dụ về cách đầu ra của người đọc sẽ như thế nào (ví dụ: hiển thị các phím hay không)
ArthurG

Điều này đã làm việc cho tôi. Tôi có thể xác nhận rằng giải pháp này cũng tránh được một trường hợp phổ biến trong đó bufferedreader.readLine () "treo" mà không có lý do rõ ràng
Naren

Xin chào @DavidDomingo, nó hoạt động 100%, tôi có thể biết rằng bạn đang nhận xét giống nhau trong câu trả lời phía trên câu trả lời này (cũng hoạt động). Kiểm tra xem ở đâu đó trong mã của bạn (có thể là bộ lọc) hoặc có thể do ai đó của Spring, phương thức getReader () không được gọi trước đó, bởi vì nếu bạn gọi nó hai lần hoặc nhiều lần, nó chỉ trả về tải trọng của phương thức đầu tiên.
Dani

Chào @Dani, đó là lý do tại sao nó không hoạt động. Đầu đọc trống. Tôi nghĩ rằng RestController đọc nó trước khi bạn có thể thực hiện nó ở bất kỳ điểm cuối nào. Cách dễ nhất để lấy body là sử dụng HttpEntity.
David Domingo

31

Hãy lưu ý rằng mã của bạn khá ồn. Tôi biết chủ đề này đã cũ, nhưng dù sao thì rất nhiều người sẽ đọc nó. Bạn có thể làm điều tương tự bằng cách sử dụng thư viện ổi với:

    if ("POST".equalsIgnoreCase(request.getMethod())) {
        test = CharStreams.toString(request.getReader());
    }

3
Có lẽ nên xem xétif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
Madbreaks

Tôi nhận được java.lang.IllegalStateException: getReader () đã được gọi cho yêu cầu này
Pra_A

18

Nếu tất cả những gì bạn muốn là nội dung yêu cầu POST, bạn có thể sử dụng một phương thức như sau:

static String extractPostRequestBody(HttpServletRequest request) throws IOException {
    if ("POST".equalsIgnoreCase(request.getMethod())) {
        Scanner s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }
    return "";
}

Tín dụng cho: https://stackoverflow.com/a/5445161/1389219


1
Hãy tính đến điều request.getInputStream()đó không tôn trọng mã hóa ký tự yêu cầu request.getReader(). +1 cho liên kết mặc dù.
Vadzim

những gì nên tương đương với phương pháp PUT?
devanathan

10

Điều này hoạt động cho cả GET và POST:

@Context
private HttpServletRequest httpRequest;


private void printRequest(HttpServletRequest httpRequest) {
    System.out.println(" \n\n Headers");

    Enumeration headerNames = httpRequest.getHeaderNames();
    while(headerNames.hasMoreElements()) {
        String headerName = (String)headerNames.nextElement();
        System.out.println(headerName + " = " + httpRequest.getHeader(headerName));
    }

    System.out.println("\n\nParameters");

    Enumeration params = httpRequest.getParameterNames();
    while(params.hasMoreElements()){
        String paramName = (String)params.nextElement();
        System.out.println(paramName + " = " + httpRequest.getParameter(paramName));
    }

    System.out.println("\n\n Row data");
    System.out.println(extractPostRequestBody(httpRequest));
}

static String extractPostRequestBody(HttpServletRequest request) {
    if ("POST".equalsIgnoreCase(request.getMethod())) {
        Scanner s = null;
        try {
            s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return s.hasNext() ? s.next() : "";
    }
    return "";
}

9

Nếu phần thân yêu cầu trống, thì điều đó đơn giản có nghĩa là nó đã được sử dụng từ trước. Ví dụ: bằng một request.getParameter(), getParameterValues()hoặc getParameterMap()cuộc gọi. Chỉ cần xóa các dòng thực hiện các cuộc gọi đó khỏi mã của bạn.


Điều đó chỉ hoạt động nếu nó không phải là một tệp tải lên, như curlví dụ là, không?
Dave Newton

1
Tôi đã thử điều này. Nhưng tôi vẫn không nhận được phần thân POST. Chắc chắn là tôi đang thiếu gì đó. Chỉ cần thêm vào: Tôi đang sử dụng Tapestry để phát triển.
patel bhavin 23/11/11

3

Điều này sẽ hoạt động cho tất cả các phương thức HTTP.

public class HttpRequestWrapper extends HttpServletRequestWrapper {
    private final String body;

    public HttpRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = IOUtils.toString(request.getReader());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getBody().getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {
            }

        };
        return servletInputStream;
    }

    public String getBody() {
        return this.body;
    }
}

0

Tôi đã giải quyết tình huống đó theo cách này. Tôi đã tạo một phương thức dùng để trả về một đối tượng được trích xuất từ ​​phần thân yêu cầu, sử dụng phương thức readValue của ObjectMapper có khả năng nhận được Trình đọc.

public static <T> T getBody(ResourceRequest request, Class<T> class) {
    T objectFromBody = null;
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest(request);
        objectFromBody = objectMapper.readValue(httpServletRequest.getReader(), class);
    } catch (IOException ex) {
        log.error("Error message", ex);
    }
    return objectFromBody;
}

1
PortalUtil là gì?
Phà Kranenburg

Tôi cá rằng đây là từ Liferay, API dành riêng cho Liferay
mvmn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.