HttpServletRequestからPOSTリクエストの本文を取得します


114

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に何も追加されません。

回答:


191

Java 8では、これをより簡単でクリーンな方法で行うことができます。

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

7
このソリューションは、サードパーティに依存しない純粋なJavaであるため、私はこのソリューションを好みます。
lu_ko

49
ただし、getReaderすでに呼び出されているように、リクエストボディを再度読み取ることはできません。
Nikhil Sahu 2017年

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


読者の出力がどのように表示されるかの例(キーを表示するかどうか)を
教えていただければ助かり

これでうまくいきました。このソリューションは、明確な理由なしにbufferedreader.readLine()が "ハング"する一般的なシナリオも回避できることを確認できます
Naren

こんにちは@DavidDomingoです。100%動作します。上記の応答で同じようにコメントしていることがわかります(これも動作します)。コード内のどこかにあることを確認してください(おそらくフィルターをかける)、またはおそらくSpringの誰かがgetReader()メソッドを以前に呼び出していないためです。これを2回以上呼び出すと、最初のペイロードのみが返されるためです。
ダニ

こんにちは@ダニ、それはそれが機能しない理由です。リーダーが空です。RestControllerは、エンドポイントで実行する前にそれを読み取ると思います。ボディを取得する最も簡単な方法は、HttpEntityを使用することです。
David Domingo

31

コードがかなりうるさいことに注意してください。スレッドが古いことは知っていますが、とにかく多くの人が読んでくれます。あなたはグアバライブラリを使って同じことをすることができます:

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

3
たぶん考えてif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
みよ

私は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 14

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は、例のように、ファイルのアップロードでない場合にのみ機能します。
デイブニュートン

1
私はこれを試しました。しかし、それでもPOSTボディを取得できません。私は何かを逃しているに違いない。追加するだけです。私は開発にタペストリーを使用しています。
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

私はそのようにしてその状況を解決しました。リーダーを受信できるObjectMapperのreadValueメソッドを使用して、リクエストの本文から抽出されたオブジェクトを返すutilメソッドを作成しました。

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とは
フェリークラネン

これはLiferay固有のAPIであるLiferayに
由来するに違いない
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.