Unshorten URL avec HttpClient

URL à raccourcir avec HttpClient

1. Vue d'ensemble

Dans cet article, nous allons montrer commentunshorten an URLs usingHttpClient.

Un exemple simple est lorsquethe original URL has been shortened once - par un service tel quebit.ly.

Un exemple plus complexe est lorsquethe URL has been shortened multiple times, par différents services de ce type, et il faut plusieurs passes pour accéder à l'URL complète d'origine.

Si vous voulez approfondir et apprendre d'autres choses intéressantes que vous pouvez faire avec HttpClient, rendez-vous surthe main HttpClient tutorial.

2. Réduire l'URL une fois

Commençons simplement: découragez une URL qui n’a été transmise qu’une seule fois à un service d’URL raccourcie.

La première chose dont nous aurons besoin est un client http quedoesn’t automatically follow redirects:

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

Cela est nécessaire car nous devrons intercepter manuellement la réponse de redirection et en extraire des informations.

Nous commençons par envoyer une requête à l'URL raccourcie - la réponse que nous obtiendrons sera un301 Moved Permanently.

Ensuite, nous devonsextract the Location header pointant vers le suivant, et dans ce cas - l'URL finale:

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();
        }
    }
}

Enfin, un simple test en direct développant une 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. Traiter plusieurs niveaux d'URL

Le problème avec les URL courtes est qu'elles peuvent êtreshortened multiple times, par des services totalement différents. L'extension d'une telle URL nécessitera plusieurs passes pour accéder à l'URL d'origine.

Nous allons appliquer l’opération primitiveexpandSingleLevel définie précédemment à simplementiterate 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;
}

Désormais, avec le nouveau mécanisme d'extension de plusieurs niveaux d'URL, définissons un test et mettons-le en œuvre:

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

Cette fois, l'URL courte -http://t.co/e4rDDbnzmk - qui est en fait raccourcie deux fois - une fois viabit.ly et une seconde fois via le servicet.co - est correctement étendue à l'URL d'origine.

4. Détecter sur les boucles de redirection

Enfin, certaines URL ne peuvent pas être développées car elles forment une boucle de redirection. Ce type de problème serait détecté par lesHttpClient, mais depuis que nous avons désactivé le suivi automatique des redirections, il ne le fait plus.

La dernière étape du mécanisme d’expansion de l’URL consiste à détecter les boucles de redirection et à échouer rapidement au cas où une telle boucle se produirait.

Pour que cela soit efficace, nous avons besoin d'informations supplémentaires sur la méthodeexpandSingleLevel que nous avons définie précédemment - principalement, nous devons également renvoyer le code d'état de la réponse avec l'URL.

Étant donné que java ne prend pas en charge plusieurs valeurs de retour, nous allons verswrap the information in a org.apache.commons.lang3.tuple.Pair object - la nouvelle signature de la méthode sera désormais:

public Pair expandSingleLevelSafe(String url) throws IOException {

Et enfin, incluons la détection du cycle de redirection dans le mécanisme d'expansion 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;
}

Et c’est tout - le mécanismeexpandSafe est capable de déprécier l’URL passant par un nombre arbitraire de services de raccourcissement d’URL, tout en échouant correctement rapidement sur les boucles de redirection.

5. Conclusion

Ce didacticiel a expliqué commentexpand short URLs in java - en utilisant ApacheHttpClient.

Nous avons commencé avec un simple cas d'utilisation avec une URL raccourcie une seule fois, puis avons mis en œuvre un mécanisme plus générique, capable de gérer plusieurs niveaux de redirections et de détecter les boucles de redirection dans le processus.

L'implémentation de ces exemples peut être trouvée dansthe github project - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel.