Enviando solicitação HTTP POST em Java

294

vamos assumir esse URL ...

http://www.example.com/page.php?id=10            

(Aqui, o ID precisa ser enviado em uma solicitação POST)

Quero enviar o id = 10para o servidor page.php, que o aceita em um método POST.

Como posso fazer isso de dentro do Java?

Eu tentei isso:

URL aaa = new URL("http://www.example.com/page.php");
URLConnection ccc = aaa.openConnection();

Mas ainda não consigo descobrir como enviá-lo via POST

Jazz
fonte

Respostas:

339

Resposta atualizada:

Como algumas classes, na resposta original, foram descontinuadas na versão mais recente do Apache HTTP Components, estou postando esta atualização.

A propósito, você pode acessar a documentação completa para mais exemplos aqui .

HttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost("http://www.a-domain.com/foo/");

// Request parameters and other properties.
List<NameValuePair> params = new ArrayList<NameValuePair>(2);
params.add(new BasicNameValuePair("param-1", "12345"));
params.add(new BasicNameValuePair("param-2", "Hello!"));
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

//Execute and get the response.
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();

if (entity != null) {
    try (InputStream instream = entity.getContent()) {
        // do something useful
    }
}

Resposta original:

Eu recomendo usar o Apache HttpClient. é mais rápido e fácil de implementar.

HttpPost post = new HttpPost("http://jakarata.apache.org/");
NameValuePair[] data = {
    new NameValuePair("user", "joe"),
    new NameValuePair("password", "bloggs")
};
post.setRequestBody(data);
// execute method and handle any error responses.
...
InputStream in = post.getResponseBodyAsStream();
// handle response.

para obter mais informações, consulte este URL: http://hc.apache.org/

mhshams
fonte
25
Depois de tentar por um tempo para chegar em minhas mãos PostMethodque parece a sua realidade agora chamado HttpPostcomo por stackoverflow.com/a/9242394/1338936 - apenas para quem encontrar esta resposta como eu fiz :)
Martin Lyne
1
@ Juan (e Martin Lyne) obrigado pelos comentários. Acabei de atualizar a resposta.
mhshams
Sua resposta revisada ainda usa hc.apache.org?
precisa saber é o seguinte
@djangofan yes. também há um link para o apache-hc na resposta revisada.
precisa saber é
6
você deve adicionar as bibliotecas importadas
gouchaoer
191

O envio de uma solicitação POST é fácil em Java vanilla. Começando com a URL, não precisamos convertê-lo em um URLConnectionuso url.openConnection();. Depois disso, precisamos convertê-lo para a HttpURLConnection, para que possamos acessar seu setRequestMethod()método para defini-lo. Finalmente dizemos que vamos enviar dados pela conexão.

URL url = new URL("https://www.example.com/login");
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection)con;
http.setRequestMethod("POST"); // PUT is another valid option
http.setDoOutput(true);

Em seguida, precisamos declarar o que vamos enviar:

Enviando um formulário simples

Um POST normal proveniente de um formulário http tem um formato bem definido . Precisamos converter nossa entrada para este formato:

Map<String,String> arguments = new HashMap<>();
arguments.put("username", "root");
arguments.put("password", "sjh76HSn!"); // This is a fake password obviously
StringJoiner sj = new StringJoiner("&");
for(Map.Entry<String,String> entry : arguments.entrySet())
    sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" 
         + URLEncoder.encode(entry.getValue(), "UTF-8"));
byte[] out = sj.toString().getBytes(StandardCharsets.UTF_8);
int length = out.length;

Podemos então anexar o conteúdo do nosso formulário à solicitação http com cabeçalhos adequados e enviá-la.

http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.connect();
try(OutputStream os = http.getOutputStream()) {
    os.write(out);
}
// Do something with http.getInputStream()

Enviando JSON

Também podemos enviar json usando java, isso também é fácil:

byte[] out = "{\"username\":\"root\",\"password\":\"password\"}" .getBytes(StandardCharsets.UTF_8);
int length = out.length;

http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
http.connect();
try(OutputStream os = http.getOutputStream()) {
    os.write(out);
}
// Do something with http.getInputStream()

Lembre-se de que servidores diferentes aceitam tipos de conteúdo diferentes para o json, consulte esta pergunta.


Enviando arquivos com publicação Java

O envio de arquivos pode ser considerado mais desafiador, pois o formato é mais complexo. Também vamos adicionar suporte para enviar os arquivos como uma string, pois não queremos armazenar o arquivo na memória.

Para isso, definimos alguns métodos auxiliares:

private void sendFile(OutputStream out, String name, InputStream in, String fileName) {
    String o = "Content-Disposition: form-data; name=\"" + URLEncoder.encode(name,"UTF-8") 
             + "\"; filename=\"" + URLEncoder.encode(filename,"UTF-8") + "\"\r\n\r\n";
    out.write(o.getBytes(StandardCharsets.UTF_8));
    byte[] buffer = new byte[2048];
    for (int n = 0; n >= 0; n = in.read(buffer))
        out.write(buffer, 0, n);
    out.write("\r\n".getBytes(StandardCharsets.UTF_8));
}

private void sendField(OutputStream out, String name, String field) {
    String o = "Content-Disposition: form-data; name=\"" 
             + URLEncoder.encode(name,"UTF-8") + "\"\r\n\r\n";
    out.write(o.getBytes(StandardCharsets.UTF_8));
    out.write(URLEncoder.encode(field,"UTF-8").getBytes(StandardCharsets.UTF_8));
    out.write("\r\n".getBytes(StandardCharsets.UTF_8));
}

Em seguida, podemos usar esses métodos para criar uma solicitação de postagem com várias partes da seguinte maneira:

String boundary = UUID.randomUUID().toString();
byte[] boundaryBytes = 
           ("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8);
byte[] finishBoundaryBytes = 
           ("--" + boundary + "--").getBytes(StandardCharsets.UTF_8);
http.setRequestProperty("Content-Type", 
           "multipart/form-data; charset=UTF-8; boundary=" + boundary);

// Enable streaming mode with default settings
http.setChunkedStreamingMode(0); 

// Send our fields:
try(OutputStream out = http.getOutputStream()) {
    // Send our header (thx Algoman)
    out.write(boundaryBytes);

    // Send our first field
    sendField(out, "username", "root");

    // Send a seperator
    out.write(boundaryBytes);

    // Send our second field
    sendField(out, "password", "toor");

    // Send another seperator
    out.write(boundaryBytes);

    // Send our file
    try(InputStream file = new FileInputStream("test.txt")) {
        sendFile(out, "identification", file, "text.txt");
    }

    // Finish the request
    out.write(finishBoundaryBytes);
}


// Do something with http.getInputStream()
Ferrybig
fonte
5
Esta publicação é útil, mas bastante falha. Levei 2 dias para fazê-lo funcionar. Portanto, para que funcione, é necessário substituir o StandartCharsets.UTF8 por StandardCharsets.UTF_8. boundaryBytes e finishBoundaryBytes precisam obter dois hífens adicionais que NÃO são transmitidos no tipo de conteúdo, portanto, boundaryBytes = ("-" + boundary + "\ r \ n"). get ... Você também precisa transmitir o boundaryBytes uma vez ANTES do primeiro campo ou o primeiro campo será ignorado!
Algoman
Por que a out.write(finishBoundaryBytes);linha precisa? http.connect();fará o envio do POST, não é?
János
16
"O envio de uma solicitação POST é fácil em Java vanilla". E, em seguida, dezenas de linhas de follow código, em comparação com algo como requests.post('http://httpbin.org/post', data = {'key':'value'})em Python ... Eu sou novo para Java de modo que este é um uso muito estranho da palavra “fácil” para me :)
Lynn
1
É relativamente mais fácil do que eu esperava considerando que é Java :)
shaahiin
enigmático \ r \ n \ r \ n significa CRLF CRLF (retorno de carro + avanço de linha). Cria 2x nova linha. A primeira nova linha é terminar a linha atual. A segunda linha é distinguir o cabeçalho http do corpo http em uma solicitação. HTTP é um protocolo baseado em ASCII. Esta é a regra para inserir \ r \ n.
Mitja Gustin #
99
String rawData = "id=10";
String type = "application/x-www-form-urlencoded";
String encodedData = URLEncoder.encode( rawData, "UTF-8" ); 
URL u = new URL("http://www.example.com/page.php");
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty( "Content-Type", type );
conn.setRequestProperty( "Content-Length", String.valueOf(encodedData.length()));
OutputStream os = conn.getOutputStream();
os.write(encodedData.getBytes());
DuduAlul
fonte
Importante notar: o uso de algo que não seja String.getBytes () parece não funcionar. Por exemplo, o uso de um PrintWriter falha totalmente.
Little Bobby Tables
5
e como definir 2 dados de postagem? Separado por dois pontos, vírgula?
gato barulhento
10
encode(String)está obsoleto. Você precisa usar encode(String, String), o que especifica o tipo de codificação. Exemplo: encode(rawData, "UTF-8").
sudo
3
Você pode querer seguir no final. Isso garantiria que a solicitação fosse concluída e o servidor tivesse a chance de processar a resposta: conn.getResponseCode ();
Szymon Jachim
3
não codifique a string inteira .. você tem que codificar apenas o valor de cada parâmetro #
user2914191 18/17/17
22

A primeira resposta foi ótima, mas tive que adicionar try / catch para evitar erros do compilador Java.
Além disso, tive problemas para descobrir como ler as HttpResponsebibliotecas Java.

Aqui está o código mais completo:

/*
 * Create the POST request
 */
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://example.com/");
// Request parameters and other properties.
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("user", "Bob"));
try {
    httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
} catch (UnsupportedEncodingException e) {
    // writing error to Log
    e.printStackTrace();
}
/*
 * Execute the HTTP Request
 */
try {
    HttpResponse response = httpClient.execute(httpPost);
    HttpEntity respEntity = response.getEntity();

    if (respEntity != null) {
        // EntityUtils to get the response content
        String content =  EntityUtils.toString(respEntity);
    }
} catch (ClientProtocolException e) {
    // writing exception to log
    e.printStackTrace();
} catch (IOException e) {
    // writing exception to log
    e.printStackTrace();
}
Mar Cnu
fonte
EntityUtils foi útil.
Jay
6
Desculpe, mas você não encontrou nenhum erro, você os apresentou. Capturar exceções em um lugar onde você não pode lidar com elas está completamente errado e e.printStackTrace()não lida com nada.
maaartinus 2/14/14
java.net.ConnectException: Conexão excedeu o tempo limite: connect
kerZy Hart
5

maneira mais simples de enviar parâmetros com a solicitação de postagem:

String postURL = "http://www.example.com/page.php";

HttpPost post = new HttpPost(postURL);

List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", "10"));

UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, "UTF-8");
post.setEntity(ent);

HttpClient client = new DefaultHttpClient();
HttpResponse responsePOST = client.execute(post);

Você fez. agora você pode usar responsePOST. Obtenha conteúdo de resposta como sequência:

BufferedReader reader = new BufferedReader(new  InputStreamReader(responsePOST.getEntity().getContent()), 2048);

if (responsePOST != null) {
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(" line : " + line);
        sb.append(line);
    }
    String getResponseString = "";
    getResponseString = sb.toString();
//use server output getResponseString as string value.
}
chandan kumar
fonte
1

Chamada HttpURLConnection.setRequestMethod("POST")e HttpURLConnection.setDoOutput(true);Na verdade, apenas o último é necessário, pois o POST se torna o método padrão.

Marquês de Lorne
fonte
que ele HttpURLConnection.setRequestMethod () :)
Jose Diaz
1

Eu recomendo usar o http-request construído no apache http api.

HttpRequest<String> httpRequest = HttpRequestBuilder.createPost("http://www.example.com/page.php", String.class)
.responseDeserializer(ResponseDeserializer.ignorableDeserializer()).build();

public void send(){
   String response = httpRequest.execute("id", "10").get();
}
Beno Arakelyan
fonte