Hacer una solicitud HTTP simple en Java

1. Información general

En este tutorial rápido, presentamos una forma de realizar solicitudes HTTP en Java , utilizando la clase Java incorporada HttpUrlConnection.

Tenga en cuenta que a partir de JDK 11, Java proporciona una nueva API para realizar solicitudes HTTP, que está pensada como un reemplazo para HttpUrlConnection, la API de HttpClient .

2. HttpUrlConnection

La clase HttpUrlConnection nos permite realizar solicitudes HTTP básicas sin el uso de bibliotecas adicionales. Todas las clases que necesitamos son parte del paquete java.net .

Las desventajas de usar este método son que el código puede ser más engorroso que otras bibliotecas HTTP y que no proporciona funcionalidades más avanzadas, como métodos dedicados para agregar encabezados o autenticación.

3. Crear una solicitud

Podemos crear una instancia de HttpUrlConnection usando el método openConnection () de la clase URL . Tenga en cuenta que este método solo crea un objeto de conexión, pero aún no establece la conexión.

La clase HttpUrlConnection se usa para todo tipo de solicitudes estableciendo el atributo requestMethod en uno de los valores: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Creemos una conexión a una URL determinada usando el método GET:

URL url = new URL("//example.com"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET");

4. Agregar parámetros de solicitud

Si queremos agregar parámetros a una solicitud, tenemos que establecer la propiedad doOutput en verdadero , luego escribir una Cadena de la forma param1 = valor¶m2 = valor en OutputStream de la instancia HttpUrlConnection :

Map parameters = new HashMap(); parameters.put("param1", "val"); con.setDoOutput(true); DataOutputStream out = new DataOutputStream(con.getOutputStream()); out.writeBytes(ParameterStringBuilder.getParamsString(parameters)); out.flush(); out.close();

Para facilitar la transformación del parámetro Map , hemos escrito una clase de utilidad llamada ParameterStringBuilder que contiene un método estático, getParamsString () , que transforma un Map en una String del formato requerido:

public class ParameterStringBuilder { public static String getParamsString(Map params) throws UnsupportedEncodingException{ StringBuilder result = new StringBuilder(); for (Map.Entry entry : params.entrySet()) { result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); result.append("&"); } String resultString = result.toString(); return resultString.length() > 0 ? resultString.substring(0, resultString.length() - 1) : resultString; } }

5. Configuración de encabezados de solicitud

Se puede agregar encabezados a una solicitud mediante el método setRequestProperty () :

con.setRequestProperty("Content-Type", "application/json");

Para leer el valor de un encabezado de una conexión, podemos usar el método getHeaderField () :

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

6. Configuración de tiempos de espera

La clase HttpUrlConnection permite configurar los tiempos de espera de conexión y lectura. Estos valores definen el intervalo de tiempo de espera para que se establezca la conexión con el servidor o que los datos estén disponibles para lectura.

Para establecer los valores de tiempo de espera, podemos usar los métodos setConnectTimeout () y setReadTimeout () :

con.setConnectTimeout(5000); con.setReadTimeout(5000);

En el ejemplo, establecemos ambos valores de tiempo de espera en cinco segundos.

7. Manejo de cookies

El paquete java.net contiene clases que facilitan el trabajo con cookies como CookieManager y HttpCookie .

Primero, para leer las cookies de una respuesta , podemos recuperar el valor del encabezado Set-Cookie y analizarlo en una lista de objetos HttpCookie :

String cookiesHeader = con.getHeaderField("Set-Cookie"); List cookies = HttpCookie.parse(cookiesHeader);

A continuación, agregaremos las cookies a la tienda de cookies :

cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));

Verifiquemos si hay una cookie llamada nombre de usuario , y si no, la agregaremos a la tienda de cookies con un valor de "john":

Optional usernameCookie = cookies.stream() .findAny().filter(cookie -> cookie.getName().equals("username")); if (usernameCookie == null) { cookieManager.getCookieStore().add(null, new HttpCookie("username", "john")); }

Finalmente, para agregar las cookies a la solicitud , necesitamos configurar el encabezado de Cookie , después de cerrar y reabrir la conexión:

con.disconnect(); con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("Cookie", StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));

8. Manejo de redireccionamientos

Podemos habilitar o deshabilitar automáticamente los siguientes redireccionamientos para una conexión específica usando el método setInstanceFollowRedirects () con el parámetro verdadero o falso :

con.setInstanceFollowRedirects(false);

También es posible habilitar o deshabilitar el redireccionamiento automático para todas las conexiones :

HttpUrlConnection.setFollowRedirects(false);

De forma predeterminada, el comportamiento está habilitado.

Cuando una solicitud devuelve un código de estado 301 o 302, que indica una redirección, podemos recuperar el encabezado de Ubicación y crear una nueva solicitud a la nueva URL:

if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM) { String location = con.getHeaderField("Location"); URL newUrl = new URL(location); con = (HttpURLConnection) newUrl.openConnection(); }

9. Leer la respuesta

Se puede leer la respuesta de la solicitud analizando el InputStream de la instancia de HttpUrlConnection .

Para ejecutar la solicitud, podemos utilizar el getResponseCode () , connect () , getInputStream () o getOutputStream () métodos :

int status = con.getResponseCode();

Finalmente, leamos la respuesta de la solicitud y colóquela en una Cadena de contenido :

BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer content = new StringBuffer(); while ((inputLine = in.readLine()) != null) { content.append(inputLine); } in.close();

Para cerrar la conexión , podemos usar el método desconectar () :

con.disconnect(); 

10. Leer la respuesta a solicitudes fallidas

Si la solicitud falla, intentar leer InputStream de la instancia de HttpUrlConnection no funcionará. En su lugar, podemos consumir el flujo proporcionado por HttpUrlConnection.getErrorStream () .

Podemos decidir qué InputStream usar comparando el código de estado HTTP:

int status = con.getResponseCode(); Reader streamReader = null; if (status > 299) { streamReader = new InputStreamReader(con.getErrorStream()); } else { streamReader = new InputStreamReader(con.getInputStream()); }

Y finalmente, podemos leer el streamReader de la misma forma que en la sección anterior.

11. Construyendo la respuesta completa

No es posible obtener la representación de respuesta completa mediante la instancia de HttpUrlConnection .

Sin embargo, podemos construirlo usando algunos de los métodos que ofrece la instancia HttpUrlConnection :

public class FullResponseBuilder { public static String getFullResponse(HttpURLConnection con) throws IOException { StringBuilder fullResponseBuilder = new StringBuilder(); // read status and message // read headers // read response content return fullResponseBuilder.toString(); } }

Aquí, leemos las partes de las respuestas, incluido el código de estado, el mensaje de estado y los encabezados, y los agregamos a una instancia de StringBuilder .

Primero, agreguemos la información del estado de la respuesta :

fullResponseBuilder.append(con.getResponseCode()) .append(" ") .append(con.getResponseMessage()) .append("\n");

A continuación, obtendremos los encabezados usando getHeaderFields () y agregaremos cada uno de ellos a nuestro StringBuilder en el formato HeaderName: HeaderValues :

con.getHeaderFields().entrySet().stream() .filter(entry -> entry.getKey() != null) .forEach(entry -> { fullResponseBuilder.append(entry.getKey()).append(": "); List headerValues = entry.getValue(); Iterator it = headerValues.iterator(); if (it.hasNext()) { fullResponseBuilder.append(it.next()); while (it.hasNext()) { fullResponseBuilder.append(", ").append(it.next()); } } fullResponseBuilder.append("\n"); });

Finalmente, leeremos el contenido de la respuesta como lo hicimos anteriormente y lo agregaremos.

Tenga en cuenta que el método getFullResponse validará si la solicitud fue exitosa o no para decidir si necesita usar con.getInputStream () o con.getErrorStream () para recuperar el contenido de la solicitud.

12. Conclusión

En este artículo, mostramos cómo podemos realizar solicitudes HTTP utilizando la clase HttpUrlConnection .

El código fuente completo de los ejemplos se puede encontrar en GitHub.