1. 概要

この記事では、 HttpClientを使用してURLを拡張する方法を紹介します。

簡単な例は、元のURLがに一度短縮された場合です– bit.lyなどのサービスによって。

より複雑な例は、さまざまなサービスによって URLが複数回短縮され、元の完全なURLに到達するまでに複数のパスが必要な場合です。

深く掘り下げて、HttpClientでできる他のクールなことを学びたい場合は、メインのHttpClientチュートリアルに進んでください。

2. URLを1回展開する

短縮URLサービスを1回だけ通過したURLを展開して、簡単に始めましょう。

最初に必要なのは、がリダイレクトを自動的にたどらないHTTPクライアントです。

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

これが必要なのは、リダイレクト応答を手動でインターセプトして、そこから情報を抽出する必要があるためです。

まず、短縮URLにリクエストを送信します。返される応答は、 301 MovedPermanentlyになります。

次に、次のURL(この場合は最終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 final void givenShortenedOnce_whenUrlIsExpanded_thenCorrectResult() throws IOException {
    final String expectedResult = "https://www.baeldung.com/rest-versioning";
    final String actualResult = expandSingleLevel("http://bit.ly/3LScTri");
    assertThat(actualResult, equalTo(expectedResult));
}

3. 複数のURLレベルを処理する

短いURLの問題は、まったく異なるサービスによって複数回短縮される可能性があることです。 このようなURLを展開すると、元のURLに到達するために複数のパスが必要になります。

前に定義したexpandSingleLevelプリミティブ操作を適用して、すべての中間URLを単純に反復し、最終的なターゲットに到達します。

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 final void givenShortenedMultiple_whenUrlIsExpanded_thenCorrectResult() throws IOException {
    final String expectedResult = "https://www.baeldung.com/rest-versioning";
    final String actualResult = expand("http://t.co/e4rDDbnzmk");
    assertThat(actualResult, equalTo(expectedResult));
}

今回は、短いURL – http://t.co/e4rDDbnzmk –実際には2回短縮されます–1回目はbit.ly経由、2回目はt経由.co サービス–元のURLに正しく展開されます。

4. リダイレクトループで検出

最後に、一部のURLは、リダイレクトループを形成するため、展開できません。 このタイプの問題はHttpClientによって検出されますが、リダイレクトの自動フォローをオフにしたため、検出されなくなりました。

URL拡張メカニズムの最後のステップは、リダイレクトループを検出し、そのようなループが発生した場合に迅速に失敗することです。

これを有効にするには、前に定義した expandSingleLevel メソッドからいくつかの追加情報が必要です。主に、URLとともに応答のステータスコードも返す必要があります。

javaは複数の戻り値をサポートしていないため、情報をorg.apache.commons.lang3.tuple.Pairオブジェクトラップします。メソッドの新しいシグネチャは次のようになります。 :

public Pair<Integer, String> expandSingleLevelSafe(String url) throws IOException {

そして最後に、リダイレクトサイクル検出をメインの展開メカニズムに含めましょう。

public String expandSafe(String urlArg) throws IOException {
    String originalUrl = urlArg;
    String newUrl = expandSingleLevelSafe(originalUrl).getRight();
    List<String> alreadyVisited = Lists.newArrayList(originalUrl, newUrl);
    while (!originalUrl.equals(newUrl)) {
        originalUrl = newUrl;
        Pair<Integer, String> 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. 結論

このチュートリアルでは、Apache HttpClient を使用して、javaで短縮URLを拡張する方法について説明しました。

最初にURLを1回だけ短縮する単純なユースケースから始めて、複数のレベルのリダイレクトを処理し、プロセス内のリダイレクトループを検出できる、より一般的なメカニズムを実装しました。

これらの例の実装は、GitHubから入手できます。