Cómo enviar solicitudes HTTP en Java

    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.

     

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *