Отмена URL-адресов с помощью HttpClient

Отмена ссылки с помощью HttpClient

1. обзор

В этой статье мы покажем, какunshorten an URLs usingHttpClient.

Простой пример -the original URL has been shortened once - службой, напримерbit.ly.

Более сложный пример -the URL has been shortened multiple times разными такими службами, и требуется несколько проходов для перехода к исходному полному URL-адресу.

Если вы хотите копнуть глубже и узнать о других интересных вещах, которые можно сделать с помощью HttpClient, перейдите кthe main HttpClient tutorial.

2. Сократите URL один раз

Давайте начнем с простого - отрежьте URL, который был передан через службу сокращения URL только один раз.

Первым делом нам понадобится http-клиент, которыйdoesn’t automatically follow redirects:

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

Это необходимо, потому что нам нужно будет вручную перехватить ответ перенаправления и извлечь из него информацию.

Начнем с отправки запроса на сокращенный URL - ответ, который мы получим, будет301 Moved Permanently.

Затем нам нужно, чтобыextract the Location header указывал на следующий, и в данном случае - на конечный URL:

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

Наконец, простой живой тест, расширяющий 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. Обработка нескольких уровней URL

Проблема с короткими URL-адресами в том, что они могут бытьshortened multiple times совершенно разными службами. Для расширения такого URL потребуется несколько проходов, чтобы добраться до исходного URL.

Мы собираемся применить примитивную операциюexpandSingleLevel, определенную ранее, просто кiterate 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;
}

Теперь, с новым механизмом расширения нескольких уровней URL-адресов, давайте определим тест и запустим его на работу:

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

На этот раз короткий URL-адрес -http://t.co/e4rDDbnzmk - который фактически сокращается дважды - один раз черезbit.ly и второй раз через службуt.co - правильно расширяется до исходного URL.

4. Обнаружение при переадресации петель

Наконец, некоторые URL не могут быть расширены, потому что они образуют цикл перенаправления. Этот тип проблемы может быть обнаруженHttpClient, но поскольку мы отключили автоматическое отслеживание перенаправлений, этого больше не происходит.

Последний шаг в механизме расширения URL будет состоять в обнаружении циклов перенаправления и быстром сбое в случае возникновения такого цикла.

Чтобы это было эффективно, нам нужна дополнительная информация из методаexpandSingleLevel, который мы определили ранее - в основном, нам нужно также вернуть код состояния ответа вместе с URL-адресом.

Поскольку java не поддерживает несколько возвращаемых значений, мы перейдем кwrap the information in a org.apache.commons.lang3.tuple.Pair object - теперь новая сигнатура метода будет:

public Pair expandSingleLevelSafe(String url) throws IOException {

И, наконец, давайте включим определение цикла перенаправления в основной механизм развертывания:

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

Вот и все - механизмexpandSafe может сокращать URL-адрес, проходящий через произвольное количество служб сокращения URL-адресов, при этом быстро не справляется с циклами перенаправления.

5. Заключение

В этом руководстве обсуждалось, какexpand short URLs in java - используя ApacheHttpClient.

Мы начали с простого сценария использования с URL-адресом, который сокращен только один раз, а затем реализовали более общий механизм, способный обрабатывать несколько уровней перенаправлений и обнаруживать циклы перенаправления в процессе.

Реализацию этих примеров можно найти вthe github project - это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.