Obtendo payload de solicitação de solicitação POST no servlet Java

113

Eu tenho uma biblioteca javascript que está enviando uma solicitação POST para meu servlet Java, mas no doPostmétodo, não consigo obter o conteúdo da carga útil da solicitação. No Chrome Developer Tools, todo o conteúdo está na seção Request Payload na guia headers, e o conteúdo está lá, e eu sei que o POST está sendo recebido pelo método doPost, mas só fica em branco.

Para o HttpServletRequest objeto, como posso obter os dados na carga útil da solicitação?

Fazer request.getParameter()ou request.getAttributes() ambos acabam sem dados

Fasih Awan
fonte
você precisa especificar qual parâmetro, por exemplo, se você tem uma palavra-chave no corpo, use String keyword = request.getParameter ("keyword");
justMe
Seria interessante ver o código JavaScript enviando a solicitação. Aparentemente, ele está compondo os parâmetros da solicitação de maneira incorreta.
BalusC de
@Razh bem sim, eu sei, eu estava apenas especificando quais métodos eu estava tentando. BalusC Estou usando a biblioteca resumable.js para lidar com uploads de arquivos divididos
Fasih Awan
4
Se não estou enganado, é importante que você NÃO use request.getParameter () antes de ler o fluxo de entrada, caso contrário, nenhum dado estará disponível (já lido).
Jeach

Respostas:

110

Resposta simples:
use getReader () para ler o corpo da solicitação

Mais informações:
Existem dois métodos para ler os dados no corpo:

  1. getReader()retorna um BufferedReader que permitirá que você leia o corpo da solicitação.

  2. getInputStream()retorna um ServletInputStream se você precisar ler dados binários.

Observação dos documentos: "[Qualquer método] pode ser chamado para ler o corpo, não ambos."

Davidfrancis
fonte
4
Sem problemas, está um pouco escondido aquele
davidfrancis
25
Esta postagem pode ser útil se você acabou de usar isso em um filtro e depois descobriu que nada mais pode ler o corpo novamente! natch3z.blogspot.co.uk/2009/01/read-request-body-in-filter.html
JonnyRaa
Esta é uma resposta muito ruim.
SgtPooki de
1
@SgtPooki sinta-se à vontade para acrescentar algumas razões para esse comentário, meu bom senhor!
davidfrancis
@davidfrancis Não estou tentando julgá-lo pessoalmente aqui, mas: você não forneceu nenhum contexto .. nenhum link para documentação, nenhum exemplo. Sua resposta ao meu comentário parece ter exigido mais esforço do que a resposta em si.
SgtPooki de
68
String payloadRequest = getBody(request);

Usando este método

public static String getBody(HttpServletRequest request) throws IOException {

    String body = null;
    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;

    try {
        InputStream inputStream = request.getInputStream();
        if (inputStream != null) {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead = -1;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                stringBuilder.append(charBuffer, 0, bytesRead);
            }
        } else {
            stringBuilder.append("");
        }
    } catch (IOException ex) {
        throw ex;
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                throw ex;
            }
        }
    }

    body = stringBuilder.toString();
    return body;
}
Adrian Ayala Torres
fonte
6
Leve em consideração que request.getInputStream()isso não respeita a codificação de caracteres da solicitação como o request.getReader()faz. Portanto, este exemplo usa o conjunto de caracteres do sistema padrão.
Vadzim
9
new BufferedReader(new InputStreamReader(request.getInputStream()))poderia ser simplificado para request.getReader()que já esteja armazenado em buffer e também preserva a codificação da solicitação.
Vadzim
1
Achei essa solução útil porque uma exceção foi lançada: javax.servlet.ServletException: java.lang.IllegalStateException: getInputStream() has already been called for this requestquando chamei getReader () como resultado do leitor já estar aberto.
Benjamin Slabbert
52

Você pode usar o Buffer Reader desde a solicitação até a leitura

    // Read from request
    StringBuilder buffer = new StringBuilder();
    BufferedReader reader = request.getReader();
    String line;
    while ((line = reader.readLine()) != null) {
        buffer.append(line);
    }
    String data = buffer.toString()
Fizer Khan
fonte
40

Streams Java 8

String body = request.getReader().lines()
    .reduce("", (accumulator, actual) -> accumulator + actual);
bbviana
fonte
Isso é interessante, mas parece bastante ineficiente em termos de concatenação de strings! Isso pode ser melhorado de alguma forma?
davidfrancis de
11
String body = request.getReader (). Lines (). Collect (Collectors.joining ()); também pode funcionar. Collectors.joining usa um StringBuilder por baixo do capô, aparentemente.
Oliver Kohll
3
Acho que deve request.getReader (). Lines (). Collect (joining ("\ n")) para preservar as novas linhas.
Michael Böckling
No java 8, o stream será processado paralelamente, portanto, é necessário adicionar o método sequencial, caso contrário, ele mesclará a parte errada dos dados - String body = request.getReader (). Lines (). Sequential (). Reduce (System.lineSeparator (), ( acumulador, real) -> acumulador + real)
Jatin Bodarya 01 de
2
Você pode substituir (accumulator, actual) -> accumulator + actualpor String::concat.
shmosel
26

Com o Apache Commons IO, você pode fazer isso em uma linha.

IOUtils.toString(request.getReader())
Diji Adeyemo
fonte
12

Se o conteúdo do corpo for uma string em Java 8, você pode fazer:

String body = request.getReader().lines().collect(Collectors.joining());

Lloyd Rochester
fonte
5

Se você puder enviar o payload em JSON, esta é a maneira mais conveniente de ler o playload:

Classe de dados de exemplo:

public class Person {
    String firstName;
    String lastName;
    // Getters and setters ...
}

Carga útil de exemplo (corpo da solicitação):

{ "firstName" : "John", "lastName" : "Doe" }

Código para ler a carga útil no servlet (requer com.google.gson. *):

Person person = new Gson().fromJson(request.getReader(), Person.class);

Isso é tudo. Bom, fácil e limpo. Não se esqueça de definir o cabeçalho do tipo de conteúdo para application / json.

Harry Developer
fonte
2

Usando o Java 8, tente com recursos:

    StringBuilder stringBuilder = new StringBuilder();
    try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
        char[] charBuffer = new char[1024];
        int bytesRead;
        while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
            stringBuilder.append(charBuffer, 0, bytesRead);
        }
    }
Timothy Heider
fonte
1

Você só precisa

request.getParameterMap ()

para obter os parâmetros POST e GET.

O método retorna a Map<String,String[]>.

Você pode ler os parâmetros no mapa por

Map<String, String[]> map = request.getParameterMap();
//Reading the Map
//Works for GET && POST Method
for(String paramName:map.keySet()) {
    String[] paramValues = map.get(paramName);

    //Get Values of Param Name
    for(String valueOfParam:paramValues) {
        //Output the Values
        System.out.println("Value of Param with Name "+paramName+": "+valueOfParam);
    }
}
Arol
fonte
2
Cuidado: os parâmetros só estarão disponíveis se você usar a codificação application/x-www-form-urlencoded; pois multipart/form-data, aparentemente, você precisa acessar a parte do corpo request.getReader()e analisá-la manualmente.
twonkeys,