URLs não curtas com HttpClient
1. Visão geral
Neste artigo, vamos mostrar comounshorten an URLs usingHttpClient.
Um exemplo simples é quandothe original URL has been shortened once - por um serviço comobit.ly.
Um exemplo mais complexo é quandothe URL has been shortened multiple times, por diferentes desses serviços, e leva várias passagens para chegar ao URL completo original.
Se você quiser se aprofundar e aprender outras coisas legais que você pode fazer com o HttpClient - vá parathe main HttpClient tutorial.
2. Reduza o URL uma vez
Vamos começar de forma simples - abreviar um URL que só passou por um serviço de URL abreviado uma vez.
A primeira coisa que precisamos é de um cliente http quedoesn’t automatically follow redirects:
CloseableHttpClient client =
HttpClientBuilder.create().disableRedirectHandling().build();
Isso é necessário porque precisaremos interceptar manualmente a resposta de redirecionamento e extrair informações dela.
Começamos enviando uma solicitação para o URL encurtado - a resposta que receberemos será301 Moved Permanently.
Então, precisamosextract the Location header apontando para o próximo e, neste 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();
}
}
}
Por fim, um simples teste ao vivo expandindo um URL:
@Test
public void givenShortenedOnce_whenUrlIsUnshortened_thenCorrectResult() throws IOException {
String expectedResult = "/rest-versioning";
String actualResult = expandSingleLevel("http://bit.ly/13jEoS1");
assertThat(actualResult, equalTo(expectedResult));
}
3. Processar vários níveis de URL
O problema com URLs curtos é que eles podem sershortened multiple times, por serviços totalmente diferentes. A expansão desse URL precisará de várias passagens para chegar ao URL original.
Vamos aplicar a operação primitivaexpandSingleLevel definida anteriormente para simplesmenteiterate through all the intermediary URL and get to the final target:
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;
}
Agora, com o novo mecanismo de expansão de vários níveis de URLs, vamos definir um teste e colocá-lo para funcionar:
@Test
public void givenShortenedMultiple_whenUrlIsUnshortened_thenCorrectResult() throws IOException {
String expectedResult = "/rest-versioning";
String actualResult = expand("http://t.co/e4rDDbnzmk");
assertThat(actualResult, equalTo(expectedResult));
}
Desta vez, o URL curto -http://t.co/e4rDDbnzmk - que na verdade é encurtado duas vezes - uma vez por meio debit.lye uma segunda vez por meio do serviçot.co - é expandido corretamente para o URL original.
4. Detectar em loops de redirecionamento
Por fim, alguns URLs não podem ser expandidos porque formam um loop de redirecionamento. Esse tipo de problema seria detectado peloHttpClient, mas como desativamos o acompanhamento automático de redirecionamentos, ele não o faz mais.
A etapa final no mecanismo de expansão de URL será detectar os loops de redirecionamento e falhar rapidamente, caso ocorra tal loop.
Para que isso seja eficaz, precisamos de algumas informações adicionais do métodoexpandSingleLevel que definimos anteriormente - principalmente, precisamos retornar também o código de status da resposta junto com a URL.
Como o java não oferece suporte a vários valores de retorno, vamos parawrap the information in a org.apache.commons.lang3.tuple.Pair object - a nova assinatura do método agora será:
public Pair expandSingleLevelSafe(String url) throws IOException {
E, finalmente, vamos incluir a detecção do ciclo de redirecionamento no mecanismo de expansão 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;
}
E é isso - o mecanismoexpandSafe é capaz de abreviar a URL passando por um número arbitrário de serviços de encurtamento de URL, enquanto falha rapidamente nos loops de redirecionamento.
5. Conclusão
Este tutorial discutiu comoexpand short URLs in java - usando o ApacheHttpClient.
Começamos com um simples caso de usuário com uma URL que é reduzida apenas uma vez e, em seguida, implementamos um mecanismo mais genérico, capaz de lidar com vários níveis de redirecionamentos e detectar loops de redirecionamento no processo.
A implementação desses exemplos pode ser encontrada emthe github project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.