Cómo enviar solicitudes HTTP en Java

C

Introducción

Protocolo de Transferencia de Hipertexto (HTTP) es un protocolo de capa de aplicación que, sin exagerar, es prácticamente la columna vertebral de la navegación por Internet tal como la conocemos.

Se utiliza para transferir documentos hipermedia entre el cliente y el servidor y es una parte esencial de cada aplicación web, incluidas las API que utilizan la arquitectura REST.

Permite que el navegador se comunique con el servidor enviando solicitudes de ciertos documentos, ya sean documentos HTML (devueltos como las páginas que vemos) o los hipermedia (imágenes, videos, etc.) que se sirven en las páginas.

¿Cómo funciona HTTP?

Cuando decidimos visitar un sitio web, lo que sucede detrás de las cortinas es que nuestra computadora genera y envía una solicitud al servidor en el que está alojado el sitio web.

Una solicitud HTTP podría verse así:

GET /tag/java/ HTTP/1.1
Host: Pharos.sh.com
Accept: */*
User-Agent: Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion

Aquí, solicitamos que el servidor devuelva la página bajo la URL Pharos.sh.com/tag/java/ utilizando HTTP versión 1.1.

Lo que el servidor debería responder es algo como esto:

HTTP/1.1 200 OK
Date: Fri, 01 Feb 2019 22:07:06 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=dd40ff971a6cefddc4855e028541f79581549051234; expires=Sat, 01-Feb-20 22:07:06 GMT; path=/; domain=.Pharos.sh.com; HttpOnly; Secure
...

Seguido por el cuerpo de respuesta:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>java - Page 1 - Stack Abuse</title>
    <meta name="description" content="" />
    <meta name="keywords" content="">

<!-- rest of the page -->

El cuerpo de la respuesta se procesará en nuestro navegador y ¡recibiremos una página!

junto al HTTP/1.1 200 OK código de estado que hemos recibido como respuesta, hay varios otros que probablemente haya encontrado en su vida diaria:

  • 1xx: Cualquier estado que comience con ‘1’ es un estado informativo. La solicitud se recibe y se está procesando.
  • 2xx: Cualquier estado que comience con ‘2’ significa que la solicitud fue exitosa. La mayoría de las veces es 200 OK lo que simplemente significa que todo salió bien.
  • 3xx: Cualquier estado que comience con ‘3’ significa que el usuario debe ser redirigido para finalizar la acción.
  • 4xx: Cualquier estado que comience con ‘4’ indica un error del cliente. El más notorio es 404 Not Found, generalmente debido a una solicitud o sintaxis incorrecta. Junto a él, hay 400 Bad Request, 401 Unauthorized y 403 Forbidden. Estos códigos de estado son los más comunes y hay una amplia variedad de ellos.
  • 5xx: Cualquier estado que comience con ‘5’ indica un error del servidor.

los lista completa de códigos de estado HTTP es bastante largo, aunque no es mala idea repasarlo.

Envío de solicitudes con HttpURLConnection

HttpURLConnection es la clase principal de Java para manejar solicitudes y respuestas HTTP.

Utilizando HttpURLConnection está perfectamente bien para solicitudes HTTP simples, aunque si desea agregar más fácilmente cosas como encabezados o autenticación, le resultará más fácil confiar en otras bibliotecas como Apache Commons.

La forma más sencilla de instanciar el HttpURLConnection el objeto está usando el URL objeto:

URL url = new URL("https://www.Pharos.sh.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

Tipos de solicitud

Ahora que nuestro HttpURLConnection existe una instancia, podemos definir un tipo de solicitud HTTP para ella:

// For a GET request
connection.setRequestMethod("GET");

// For a POST request
connection.setRequestMethod("POST");

// For a HEAD request
connection.setRequestMethod("HEAD");

// For a OPTIONS request
connection.setRequestMethod("OPTIONS");

// For a PUT request
connection.setRequestMethod("PUT");

// For a DELETE request
connection.setRequestMethod("DELETE");

// For a TRACE request
connection.setRequestMethod("TRACE");

Sin embargo, en la mayoría de los casos solo usará GET, POST y DELETE.

Solicitar parámetros

En algunos casos, nos gustaría enviar una solicitud HTTP con ciertos parámetros de consulta, como www.youtube.com/watch?v=dQw4w9WgXcQ.

Para lograr esto, normalmente se nos ocurre una forma de emparejar estos valores. A veces, las personas definen sus propias clases para mantener estos valores, aunque una simple HashMap lo hará bien:

Map<String, String> params = new HashMap<>();
params.put("v", "dQw4w9WgXcQ");

Ahora que tenemos nuestros parámetros asignados, necesitamos hacer un par de cosas para prepararlos para nuestra solicitud:

  • Genere el parámetro en un formato similar a una cadena. Estaremos usando StringBuilder ya que es ideal para la concatenación que realizaremos
  • Utilizar el URLEncoder clase para codificar nuestros parámetros
  • Convierta los datos en bytes, como nuestro DataOutputStream que dispara la solicitud espera una matriz de tipo byte

Nota: Si no está seguro de por qué necesitamos codificar nuestra URL, es porque ciertos caracteres pueden tener un significado especial dentro de las URL. Personajes como “/”, “.”, “#”y “?” puede alterar la solicitud, por lo que, si están presentes, debemos codificarlos de una manera que no afecte la forma en que se interpreta la URL.

Implementemos los elementos de la lista:

// Instantiate a requestData object to store our data
StringBuilder requestData = new StringBuilder();

for (Map.Entry<String, String> param : params.entrySet()) {
    if (requestData.length() != 0) {
        requestData.append('&');
    }
    // Encode the parameter based on the parameter map we've defined
    // and append the values from the map to form a single parameter
    requestData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
    requestData.append('=');
    requestData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}

// Convert the requestData into bytes 
byte[] requestDataByes = requestData.toString().getBytes("UTF-8");

Y así, nuestro parámetro está listo para ser utilizado en la solicitud.

Solicitar encabezados

Si desea agregar un encabezado a una solicitud, es tan fácil como:

connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Content-Length", String.valueOf(requestDataBytes.length));

Y si desea leer un encabezado de una solicitud:

String contentType = connection.getHeaderField("Content-Type");

Tiempos de espera

Otra característica HttpURLConnection ofertas está estableciendo tiempos muertos. Podemos definir intervalos de tiempo de espera para leer o conectarse:

connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);

Los intervalos, como de costumbre, se definen en milisegundos.

Entonces, por ejemplo, la conexión expirará si no se puede establecer en 10 segundos. Del mismo modo, también se agotará el tiempo de espera si no se pueden leer los datos de la conexión en 10 segundos.

Solicitud POST

Con nuestra solicitud configurada, podemos continuar y disparar la solicitud POST:

// Set the doOutput flag to true
connection.setDoOutput(true);

// Get the output stream of the connection instance
// and add the parameter to the request
try (DataOutputStream writer = new DataOutputStream(connection.getOutputStream())) {
    writer.write(postDataBytes);

    // Always flush and close
    writer.flush();
    writer.close();
}

Aquí estamos enviando postDataBytes en nuestra solicitud POST, que es una matriz de bytes. Consulte la demostración a continuación para obtener más detalles sobre cómo generar esto.

OBTENER Solicitud

Una vez que enviamos una solicitud POST, normalmente querríamos hacer algo para (o al menos ver) la respuesta.

Las solicitudes GET solo están destinadas a recuperar datos, así que sigamos adelante y obtengamos una respuesta:

// To store our response
StringBuilder content;

// Get the input stream of the connection
try (BufferedReader input = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
    String line;
    content = new StringBuilder();
    while ((line = input.readLine()) != null) {
        // Append each line of the response and separate them
        content.append(line);
        content.append(System.lineSeparator());
    }
} finally {
    connection.disconnect();
}

// Output the content to the console
System.out.println(content.toString());

Podemos extraer muchos tipos diferentes de información del connection en este punto:

// Returns the value of the content-type header field
connection.getContentType();

// Returns an unmodifiable Map of the header fields
connection.getHeaderFields();

// Gets the status code from an HTTP response message
connection.getResponseCode();

// Gets the HTTP response message returned along with the response code from a server
connection.getResponseMessage();

// Returns the error stream if the connection failed but the server sent useful data nonetheless
connection.getErrorStream();

// ...etc

Manifestación

Así es como una aplicación muy simple generaría una solicitud POST, la enviaría y luego leería la respuesta:

public static void main(String[] args) throws MalformedURLException, ProtocolException, IOException {
    URL url = new URL("https://www.youtube.com");
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();

    connection.setRequestMethod("POST");
    Map<String, String> params = new HashMap<>();
    params.put("v", "dQw4w9WgXcQ");

    StringBuilder postData = new StringBuilder();
    for (Map.Entry<String, String> param : params.entrySet()) {
        if (postData.length() != 0) {
            postData.append('&');
        }
        postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
        postData.append('=');
        postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
    }

    byte[] postDataBytes = postData.toString().getBytes("UTF-8");
    connection.setDoOutput(true);
    try (DataOutputStream writer = new DataOutputStream(connection.getOutputStream())) {
        writer.write(postDataBytes);
        writer.flush();
        writer.close();

        StringBuilder content;

        try (BufferedReader in = new BufferedReader(
                new InputStreamReader(connection.getInputStream()))) {
        String line;
        content = new StringBuilder();
           while ((line = in.readLine()) != null) {
                content.append(line);
                content.append(System.lineSeparator());
            }
        }
        System.out.println(content.toString());
    } finally {
        connection.disconnect();
    }
}

Ejecutar este fragmento de código seguramente produce el código fuente de la página que especificamos para obtener:

<!DOCTYPE html>
<html lang="sr" data-cast-api-enabled="true">
<head>
<!-- rest of the page -->  

Conclusión

Protocolo de Transferencia de Hipertexto (HTTP) es un protocolo de capa de aplicación que, sin exagerar, es un componente muy grande y crítico para las aplicaciones de Internet.

HttpURLConnection es la clase principal de Java para manejar solicitudes y respuestas HTTP.

Utilizando HttpURLConnection está perfectamente bien para solicitudes HTTP simples, aunque si desea crear solicitudes HTTP más complejas con encabezados o autenticación, tendrá una experiencia mucho más simple con bibliotecas como Apache Commons.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad