รับเนื้อหาคำขอ POST จาก HttpServletRequest


115

ฉันพยายามดึงทั้งร่างกายจากวัตถุ HttpServletRequest

รหัสที่ฉันกำลังติดตามมีลักษณะดังนี้:

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

และฉันกำลังทดสอบการทำงานด้วย curl และ wget ดังนี้:

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"

แต่while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 )ไม่ส่งคืนอะไรเลยดังนั้นฉันจึงไม่ได้รับอะไรต่อท้าย StringBuffer

คำตอบ:


192

ใน Java 8 คุณสามารถทำได้ด้วยวิธีที่ง่ายและสะอาดกว่า:

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

8
ฉันชอบโซลูชันนี้เนื่องจากเป็น Java บริสุทธิ์โดยไม่ต้องพึ่งพาบุคคลที่สาม
lu_ko

49
แม้ว่าโปรดจำไว้ว่าเราไม่สามารถอ่านเนื้อหาคำขอได้อีกครั้งตามที่getReaderเรียกไปแล้ว
Nikhil Sahu

1
เราจะตั้งค่าข้อมูล HTTP POST ที่จัดรูปแบบใหม่กลับมาเป็นคำขอได้อย่างไร
Pra_A

1
ฉันได้ลองวิธีแก้ปัญหานี้แล้ว แต่มันนำเสนอปัญหาที่ร้ายแรงมากฉันใช้รหัสนี้เพื่อบันทึกข้อมูลการร้องขอภายในตัวกรอง oncePerRequest และเมื่อฉันใช้มันการผูก @modelAttribute ทั้งหมดของฉันในวิธีการโพสต์ทั้งหมดของฉันจะให้ค่าว่างในทุกฟิลด์ของ วัตถุฉันไม่แนะนำให้ใช้วิธีนี้
Mohammed Fathi

เราไม่ควรปิดเครื่องอ่าน?
aristo_sh

46

วิธีง่ายๆด้วย commons-io

IOUtils.toString(request.getReader());

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


ฉันจะช่วยถ้าคุณสามารถให้ตัวอย่างว่าผลลัพธ์ของเครื่องอ่านจะเป็นอย่างไร (เช่นแสดงคีย์หรือไม่)
ArthurG

สิ่งนี้ได้ผลสำหรับฉัน ฉันสามารถยืนยันได้ว่าโซลูชันนี้ยังหลีกเลี่ยงสถานการณ์ทั่วไปที่ bufferedreader.readLine () "ค้าง" โดยไม่มีเหตุผลชัดเจน
เรนทร์

สวัสดี @DavidDomingo มันใช้งานได้ 100% ฉันสามารถอ่านได้ว่าคุณกำลังแสดงความคิดเห็นเหมือนกันในการตอบกลับด้านบนนี้ (ซึ่งได้ผลเช่นกัน) ตรวจสอบว่ามีบางส่วนในรหัสของคุณ (กรองได้อย่างน่าจะเป็น) หรืออาจเป็นเพราะใครบางคนใน Spring จึงไม่ได้เรียกเมธอด getReader () มาก่อนเพราะถ้าคุณเรียกมันสองครั้งหรือมากกว่านั้นจะส่งคืนเฉพาะส่วนแรกเท่านั้น
Dani

สวัสดี @Dani นั่นเป็นสาเหตุที่ไม่ได้ผล ผู้อ่านว่างเปล่า ฉันคิดว่า RestController อ่านก่อนที่คุณจะสามารถทำได้ในจุดสิ้นสุดใด ๆ วิธีที่ง่ายที่สุดในการรับร่างกายคือการใช้ HttpEntity
David Domingo

31

โปรดทราบว่ารหัสของคุณค่อนข้างมีเสียงดัง ฉันรู้ว่ากระทู้เก่า แต่ก็มีคนอ่านเยอะอยู่ดี คุณสามารถทำสิ่งเดียวกันโดยใช้guava library กับ:

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

3
บางทีอาจจะพิจารณาif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
Madbreaks

ฉันได้รับ java.lang.IllegalStateException: getReader () ถูกเรียกสำหรับคำขอนี้แล้ว
Pra_A

18

หากสิ่งที่คุณต้องการคือเนื้อหาคำขอ POST คุณสามารถใช้วิธีการดังนี้:

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

เครดิตไปที่: https://stackoverflow.com/a/5445161/1389219


1
คำนึงถึงสิ่งที่request.getInputStream()ไม่เป็นไปตามการเข้ารหัสอักขระคำขอเช่นเดียวกับที่request.getReader()ทำ +1 สำหรับลิงก์แม้ว่า
Vadzim

สิ่งที่ควรจะเทียบเท่ากับวิธี PUT?
devanathan

10

สิ่งนี้ใช้ได้กับทั้ง GET และ 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

หากเนื้อหาคำขอว่างเปล่าแสดงว่ามีการใช้ไปแล้วก่อนหน้านี้ ยกตัวอย่างเช่นโดยrequest.getParameter(), getParameterValues()หรือgetParameterMap()โทร เพียงแค่ลบบรรทัดที่โทรออกจากรหัสของคุณ


จะใช้งานได้ก็ต่อเมื่อไม่ใช่การอัปโหลดไฟล์ดังcurlตัวอย่างไม่ใช่?
Dave Newton

1
ฉันลองสิ่งนี้ แต่ถึงกระนั้นฉันก็ยังไม่ได้รับร่างโพสต์ ฉันต้องขาดอะไรบางอย่าง เพื่อเพิ่ม: ฉันใช้ Tapestry ในการพัฒนา
patel bhavin

3

วิธีนี้จะใช้ได้กับวิธี 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

ฉันแก้ไขสถานการณ์นั้นด้วยวิธีนี้ ฉันสร้างเมธอด util ที่ส่งคืนอ็อบเจ็กต์ที่ดึงออกมาจากคำร้องขอโดยใช้เมธอด readValue ของ ObjectMapper ที่สามารถรับ 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;
}

1
PortalUtil คืออะไร?
เรือเฟอร์รี่ Kranenburg

ฉันพนันได้เลยว่านี่มาจาก Liferay API เฉพาะของ Liferay
mvmn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.