Desviar URL con HttpClient

1. Información general

En este artículo vamos a mostrar cómo acortar una URL usando HttpClient .

Un ejemplo sencillo es cuando la URL original se ha reducido una vez - por un servicio como bit.ly .

Un ejemplo más complejo es cuando la URL se ha acortado varias veces , por diferentes servicios de este tipo, y se necesitan varias pasadas para llegar a la URL completa original.

Si desea profundizar y aprender otras cosas interesantes que puede hacer con HttpClient, diríjase al tutorial principal de HttpClient .

2. Anule la reducción de la URL una vez

Comencemos de manera simple: reduzca una URL que solo se haya pasado a través de un servicio de URL acortada una vez.

Lo primero que necesitaremos es un cliente http que no siga automáticamente las redirecciones :

CloseableHttpClient client = HttpClientBuilder.create().disableRedirectHandling().build();

Esto es necesario porque necesitaremos interceptar manualmente la respuesta de redireccionamiento y extraer información de ella.

Comenzamos enviando una solicitud a la URL abreviada; la respuesta que recibiremos será un 301 Moved Permanently .

Luego, necesitamos extraer el encabezado de Ubicación apuntando al siguiente, y en este caso, URL final:

public String expandSingleLevel(String url) throws IOException { HttpHead request = null; try { request = new HttpHead(url); HttpResponse httpResponse = client.execute(request); int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode != 301 && statusCode != 302) { return url; } Header[] headers = httpResponse.getHeaders(HttpHeaders.LOCATION); Preconditions.checkState(headers.length == 1); String newUrl = headers[0].getValue(); return newUrl; } catch (IllegalArgumentException uriEx) { return url; } finally { if (request != null) { request.releaseConnection(); } } }

Finalmente, una simple prueba en vivo expandiendo una URL:

@Test public void givenShortenedOnce_whenUrlIsUnshortened_thenCorrectResult() throws IOException { String expectedResult = "/rest-versioning"; String actualResult = expandSingleLevel("//bit.ly/13jEoS1"); assertThat(actualResult, equalTo(expectedResult)); }

3. Procesar varios niveles de URL

El problema con las URL cortas es que pueden acortarse varias veces mediante servicios completamente diferentes. La expansión de dicha URL necesitará varias pasadas para llegar a la URL original.

Vamos a aplicar la operación primitiva expandSingleLevel definida previamente para simplemente iterar a través de toda la URL intermedia y llegar al objetivo final :

public String expand(String urlArg) throws IOException { String originalUrl = urlArg; String newUrl = expandSingleLevel(originalUrl); while (!originalUrl.equals(newUrl)) { originalUrl = newUrl; newUrl = expandSingleLevel(originalUrl); } return newUrl; }

Ahora, con el nuevo mecanismo de expandir múltiples niveles de URL, definamos una prueba y pongamos esto en funcionamiento:

@Test public void givenShortenedMultiple_whenUrlIsUnshortened_thenCorrectResult() throws IOException { String expectedResult = "/rest-versioning"; String actualResult = expand("//t.co/e4rDDbnzmk"); assertThat(actualResult, equalTo(expectedResult)); }

Esta vez, la URL corta, //t.co/e4rDDbnzmk , que en realidad se acorta dos veces, una a través de bit.ly y una segunda a través del servicio t.co , se expande correctamente a la URL original.

4. Detectar en bucles de redireccionamiento

Finalmente, algunas URL no se pueden expandir porque forman un bucle de redireccionamiento. Este tipo de problema sería detectado por HttpClient , pero como desactivamos el seguimiento automático de redirecciones, ya no lo hace.

El último paso en el mecanismo de expansión de URL será detectar los bucles de redireccionamiento y fallar rápidamente en caso de que ocurra tal bucle.

Para que esto sea efectivo, necesitamos información adicional del método expandSingleLevel que definimos anteriormente; principalmente, también debemos devolver el código de estado de la respuesta junto con la URL.

Dado que java no admite múltiples valores de retorno, vamos a envolver la información en un objeto org.apache.commons.lang3.tuple.Pair ; la nueva firma del método ahora será:

public Pair expandSingleLevelSafe(String url) throws IOException {

Y finalmente, incluyamos la detección del ciclo de redireccionamiento en el mecanismo de expansión principal:

public String expandSafe(String urlArg) throws IOException { String originalUrl = urlArg; String newUrl = expandSingleLevelSafe(originalUrl).getRight(); List alreadyVisited = Lists.newArrayList(originalUrl, newUrl); while (!originalUrl.equals(newUrl)) { originalUrl = newUrl; Pair statusAndUrl = expandSingleLevelSafe(originalUrl); newUrl = statusAndUrl.getRight(); boolean isRedirect = statusAndUrl.getLeft() == 301 || statusAndUrl.getLeft() == 302; if (isRedirect && alreadyVisited.contains(newUrl)) { throw new IllegalStateException("Likely a redirect loop"); } alreadyVisited.add(newUrl); } return newUrl; }

Y eso es todo: el mecanismo expandSafe es capaz de acortar la URL que atraviesa una cantidad arbitraria de servicios de acortamiento de URL, mientras falla correctamente y rápidamente en los bucles de redireccionamiento.

5. Conclusión

Este tutorial discutió cómo expandir URL cortas en java , usando Apache HttpClient .

Comenzamos con un caso de uso simple con una URL que solo se acorta una vez, y luego implementamos un mecanismo más genérico, capaz de manejar múltiples niveles de redireccionamientos y detectar bucles de redireccionamiento en el proceso.

La implementación de estos ejemplos se puede encontrar en el proyecto github; este es un proyecto basado en Eclipse, por lo que debería ser fácil de importar y ejecutar como está.