Dapatkan badan permintaan POST dari HttpServletRequest

115

Saya mencoba untuk mendapatkan seluruh isi dari objek HttpServletRequest.

Kode yang saya ikuti terlihat seperti ini:

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();
}

dan saya menguji fungsionalitas dengan curl dan wget sebagai berikut:

curl --header "MD5: abcd" -F "[email protected] http://localhost:8080/abcd.html"

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

Tetapi while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 )tidak mengembalikan apa pun, jadi saya tidak mendapatkan apa pun yang ditambahkan di StringBuffer.

patel bhavin
sumber

Jawaban:

192

Di Java 8, Anda dapat melakukannya dengan cara yang lebih sederhana dan bersih:

if ("POST".equalsIgnoreCase(request.getMethod())) 
{
   test = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
}
abhi
sumber
8
Saya lebih suka solusi ini karena ini adalah Java murni tanpa ketergantungan pihak ke-3.
lu_ko
49
Meskipun perlu diingat bahwa kami tidak dapat membaca badan permintaan lagi karena getReadertelah dipanggil.
Nikhil Sahu
1
Bagaimana kita bisa mengatur kembali data HTTP POST yang baru diformat kembali ke dalam permintaan?
Pra_A
1
Saya telah mencoba solusi ini tetapi memperkenalkan preblem yang sangat serius, saya menggunakan kode ini untuk mencatat info permintaan di dalam filter oncePerRequest, dan ketika saya menggunakannya, semua @modelAttribute saya yang mengikat di semua metode posting saya memberi nol di semua bidang objek. Saya tidak merekomendasikan menggunakan pendekatan ini.
Mohammed Fathi
Haruskah kita tidak menutup pembaca?
aristo_sh
46

Cara mudah dengan commons-io.

IOUtils.toString(request.getReader());

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

Dani
sumber
Saya akan membantu jika Anda dapat memberikan contoh bagaimana keluaran pembaca akan terlihat (yaitu, tunjukkan kunci atau tidak)
ArthurG
Ini berhasil untuk saya. Saya dapat mengonfirmasi bahwa solusi ini juga menghindari skenario umum di mana bufferedreader.readLine () "hang" tanpa alasan yang jelas
Naren
Hai @DavidDomingo, ini berfungsi 100%, saya dapat membaca bahwa Anda mengomentari hal yang sama dalam tanggapan di atas yang satu ini (yang juga berfungsi). Periksa bahwa di suatu tempat dalam kode Anda (memfilter dengan masalah), atau mungkin karena seseorang oleh Spring, metode getReader () tidak dipanggil sebelumnya, karena jika Anda memanggilnya dua kali atau lebih, itu hanya mengembalikan payload yang pertama.
Dani
Hai @Dani, itu sebabnya tidak berhasil. Pembaca kosong. Saya pikir RestController membacanya sebelum Anda dapat melakukannya di titik akhir mana pun. Cara termudah untuk mendapatkan body adalah dengan menggunakan HttpEntity.
David Domingo
31

Ketahuilah, kode Anda cukup berisik. Saya tahu utasnya sudah tua, tetapi banyak orang akan tetap membacanya. Anda dapat melakukan hal yang sama menggunakan pustaka jambu biji dengan:

    if ("POST".equalsIgnoreCase(request.getMethod())) {
        test = CharStreams.toString(request.getReader());
    }
afx
sumber
3
Mungkin pertimbangkanif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
Madbreaks
Saya mendapatkan java.lang.IllegalStateException: getReader () telah dipanggil untuk permintaan ini
Pra_A
18

Jika yang Anda inginkan hanyalah badan permintaan POST, Anda dapat menggunakan metode seperti ini:

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 "";
}

Kredit ke: https://stackoverflow.com/a/5445161/1389219

vegemite4me
sumber
1
Mempertimbangkan bahwa request.getInputStream()tidak menghormati pengkodean karakter permintaan seperti request.getReader()halnya. 1 untuk tautannya.
Vadzim
apa yang harus setara untuk metode PUT?
devanathan
10

Ini berfungsi untuk GET dan 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 "";
}
Bruno Lee
sumber
9

Jika isi permintaan kosong, itu berarti sudah dikonsumsi sebelumnya. Misalnya dengan panggilan request.getParameter(), getParameterValues()atau getParameterMap()panggilan. Hapus saja baris yang melakukan panggilan tersebut dari kode Anda.

BalusC
sumber
Itu hanya berfungsi jika itu bukan unggahan file, seperti curlcontohnya, bukan?
Dave Newton
1
Saya mencoba hal ini. Tapi tetap saja saya belum mendapatkan badan POST. Saya pasti melewatkan sesuatu. Sekadar menambahkan: Saya menggunakan Tapestry untuk pengembangan.
patel bhavin
3

Ini akan bekerja untuk semua metode 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;
    }
}
Bhawna Joshi
sumber
0

Saya menyelesaikan situasi itu dengan cara ini. Saya membuat metode util yang mengembalikan objek yang diekstrak dari tubuh permintaan, menggunakan metode readValue dari ObjectMapper yang mampu menerima Reader.

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;
}
Francisco Disalvo
sumber
1
apa itu PortalUtil?
Ferry Kranenburg
Saya yakin ini dari Liferay, API khusus Liferay
mvmn