Envío de solicitud HTTP POST en Java

295

supongamos que esta URL ...

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

(Aquí la identificación debe enviarse en una solicitud POST)

Quiero enviar el id = 10al servidor page.php, que lo acepta en un método POST.

¿Cómo puedo hacer esto desde Java?

Intenté esto:

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

Pero todavía no puedo entender cómo enviarlo a través de POST

Jazz
fuente

Respuestas:

339

Respuesta actualizada:

Dado que algunas de las clases, en la respuesta original, están en desuso en la versión más reciente de Apache HTTP Components, estoy publicando esta actualización.

Por cierto, puede acceder a la documentación completa para obtener más ejemplos aquí .

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

Respuesta original

Recomiendo usar Apache HttpClient. Es más rápido y más 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 obtener más información, consulte esta URL: http://hc.apache.org/

mhshams
fuente
25
Después de intentarlo durante un tiempo PostMethod, parece que en realidad ahora se llama HttpPostsegún stackoverflow.com/a/9242394/1338936 , solo para cualquiera que encuentre esta respuesta como lo hice :)
Martin Lyne
1
@Juan (y Martin Lyne) gracias por los comentarios. Acabo de actualizar la respuesta.
mhshams
¿Su respuesta revisada todavía usa hc.apache.org?
djangofan
@djangofan sí. También hay un enlace a apache-hc en la respuesta revisada.
mhshams
66
deberías agregar las
librerías
192

Enviar una solicitud POST es fácil en Java vainilla. Comenzando con a URL, necesitamos convertirlo a un URLConnectionuso url.openConnection();. Después de eso, necesitamos convertirlo en a HttpURLConnection, para que podamos acceder a su setRequestMethod()método para establecer nuestro método. Finalmente decimos que vamos a enviar datos a través de la conexión.

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

Luego tenemos que indicar lo que vamos a enviar:

Enviar un formulario simple

Una POST normal proveniente de un formulario http tiene un formato bien definido . Necesitamos convertir nuestra entrada a 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;

Luego podemos adjuntar el contenido de nuestro formulario a la solicitud http con los encabezados adecuados y enviarlo.

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

También podemos enviar json usando java, esto también es 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()

Recuerde que diferentes servidores aceptan diferentes tipos de contenido para json, vea esta pregunta.


Envío de archivos con publicación java

El envío de archivos puede considerarse más difícil de manejar ya que el formato es más complejo. También vamos a agregar soporte para enviar los archivos como una cadena, ya que no queremos almacenar el archivo en el búfer completamente en la memoria.

Para esto, definimos algunos 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));
}

Luego podemos usar estos métodos para crear una solicitud de publicación de varias partes de la siguiente manera:

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
fuente
55
Esta publicación es útil, pero bastante defectuosa. Me llevó 2 días hacerlo funcionar. Entonces, para que funcione, debe reemplazar StandartCharsets.UTF8 con StandardCharsets.UTF_8. boundaryBytes y finishBoundaryBytes necesitan obtener dos guiones adicionales que NO se transmiten en Content-Type, por lo que boundaryBytes = ("-" + boundary + "\ r \ n"). get ... También necesita transmitir los boundaryBytes una vez ¡ANTES de ignorar el primer campo o el primer campo!
Algoman
¿Por qué out.write(finishBoundaryBytes);necesita línea? http.connect();realizará el envío POST, ¿no?
János
17
"Enviar una solicitud POST es fácil en Java". Y luego siguen docenas de líneas de código, en comparación con algo como requests.post('http://httpbin.org/post', data = {'key':'value'})en Python ... Soy nuevo en Java, así que este es un uso muy extraño de la palabra "fácil" para mí :)
Lynn
1
Es relativamente más fácil de lo que esperaba teniendo en cuenta que es Java :)
shaahiin
enigmático \ r \ n \ r \ n significa CRLF CRLF (retorno de carro + avance de línea). Crea 2x nueva línea. La primera línea nueva es terminar la línea actual. La segunda línea es distinguir el encabezado http del cuerpo http en una solicitud. HTTP es un protocolo basado en ASCII. Esta es la regla para insertar \ 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
fuente
Importante tener en cuenta: el uso de cualquier otra cosa que no sea String.getBytes () no parece funcionar. Por ejemplo, el uso de un PrintWriter falla totalmente.
Little Bobby Tables
55
y cómo configurar 2 datos de publicación? Separado por dos puntos, coma?
gato ruidoso
10
encode(String)es obsoleto. Tienes que usar encode(String, String), que especifica el tipo de codificación. Ejemplo: encode(rawData, "UTF-8").
sudo
3
Es posible que desee seguir al final. Esto aseguraría que la solicitud haya finalizado y que el servidor tenga la oportunidad de procesar la respuesta: conn.getResponseCode ();
Szymon Jachim
3
no codifique la cadena completa ... debe codificar solo el valor de cada parámetro
user2914191
22

La primera respuesta fue excelente, pero tuve que agregar try / catch para evitar errores del compilador de Java.
Además, tuve problemas para entender cómo leer las HttpResponsebibliotecas Java.

Aquí está el código más 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
fuente
EntityUtils fue útil.
Jay
66
Lo sentimos, pero no captó ningún error, los introdujo. Capturar excepciones en un lugar donde no puede manejarlas es simplemente incorrecto y e.printStackTrace()no maneja nada.
maaartinus
java.net.ConnectException: Se agotó el tiempo de espera de la conexión: connect
kerZy Hart
5

La forma más sencilla de enviar parámetros con la solicitud de publicación:

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

Has hecho. ahora puedes usar responsePOST. Obtener contenido de respuesta como cadena:

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
fuente
1

Llamar HttpURLConnection.setRequestMethod("POST")y, en HttpURLConnection.setDoOutput(true);realidad, solo se necesita este último ya que POST se convierte en el método predeterminado.

Marqués de Lorne
fuente
it it HttpURLConnection.setRequestMethod () :)
Jose Diaz
1

Recomiendo usar http-request construido en 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
fuente