Obtenha o corpo da solicitação POST de HttpServletRequest


114

Estou tentando obter o corpo inteiro do objeto HttpServletRequest.

O código que estou seguindo é assim:

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

e estou testando a funcionalidade com curl e wget da seguinte maneira:

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"

Mas o while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 )não retorna nada e, portanto, não recebo nada anexado a StringBuffer.

Respostas:


191

No Java 8, você pode fazer isso de uma maneira mais simples e limpa:

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

7
Prefiro essa solução por ser um Java puro sem nenhuma dependência de terceiros.
lu_ko

49
Porém, tenha em mente que não podemos ler o corpo da solicitação novamente, pois getReaderjá foi chamado.
Nikhil Sahu

1
Como podemos restaurar os dados HTTP POST recém-formatados de volta à solicitação?
Pra_A

1
Eu tentei essa solução, mas ela apresentou um problema muito sério, usei esse código para registrar informações de solicitação dentro de um filtro oncePerRequest e, quando o usei, todas as minhas ligações @modelAttribute em todos os meus métodos de postagem deram null em todos os campos de um objeto .Eu não recomendo usar esta abordagem.
Mohammed Fathi

Não deveríamos fechar o leitor?
aristo_sh

46

Maneira fácil com o commons-io.

IOUtils.toString(request.getReader());

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


Eu ajudaria se você pudesse dar um exemplo de como seria a saída do leitor (ou seja, mostrar as chaves ou não)
ArthurG

Isso funcionou para mim. Posso confirmar que essa solução também evita um cenário comum em que bufferedreader.readLine () "trava" sem motivo aparente
Naren

Olá @DavidDomingo, funciona 100%, posso ler que você está comentando o mesmo na resposta acima (que também funciona). Verifique se em algum lugar do seu código (provavelmente os filtros), ou talvez porque alguém do Spring, o método getReader () não foi chamado antes, porque se você chamá-lo duas ou mais vezes, ele retornará a carga útil apenas na primeira.
Dani

Olá @Dani, é por isso que não funciona. O leitor está vazio. Acho que o RestController lê antes que você seja capaz de fazer em qualquer endpoint. A maneira mais fácil de obter o corpo é usando HttpEntity.
David Domingo

31

Esteja ciente de que seu código é muito barulhento. Eu sei que o tópico é antigo, mas muitas pessoas irão ler de qualquer maneira. Você poderia fazer a mesma coisa usando a biblioteca de goiaba com:

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

3
Talvez considereif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
Madbreaks

Eu recebo o java.lang.IllegalStateException: getReader () já foi chamado para esta solicitação
Pra_A

18

Se tudo o que você deseja é o corpo da solicitação POST, você pode usar um método como este:

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

Crédito para: https://stackoverflow.com/a/5445161/1389219


1
Leve em consideração que request.getInputStream()isso não respeita a codificação de caracteres da solicitação como request.getReader()faz. 1 para o link embora.
Vadzim

qual deve ser o equivalente para o método PUT?
devanathan

10

Isso funciona para GET e 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

Se o corpo da solicitação estiver vazio, isso significa simplesmente que já foi consumido de antemão. Por exemplo, por um request.getParameter(), getParameterValues()ou getParameterMap()chamada. Apenas remova as linhas que fazem essas chamadas de seu código.


Isso só funciona se não for um upload de arquivo, como é o curlexemplo, não?
Dave Newton

1
Eu tentei isso. Mas ainda não estou recebendo o corpo do POST. Eu devo estar esquecendo alguma coisa. Só para acrescentar: estou usando Tapestry para o desenvolvimento.
patel bhavin

3

Isso funcionará para todos os métodos 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

Resolvi essa situação desta forma. Criei um método utilitário que retorna um objeto extraído do corpo da solicitação, usando o método readValue do ObjectMapper que é capaz de receber um 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
o que é PortalUtil?
Ferry Kranenburg

Aposto que é do Liferay, API específica do Liferay
mvmn
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.