HttpClientでURLを短縮しない
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を1回短縮します
簡単に始めましょう–短縮URLサービスを1回だけ通過したURLを短縮解除します。
最初に必要なのは、doesn’t automatically follow redirectsのhttpクライアントです。
CloseableHttpClient client =
HttpClientBuilder.create().disableRedirectHandling().build();
これが必要なのは、リダイレクトレスポンスを手動でインターセプトし、そこから情報を抽出する必要があるためです。
まず、短縮URLにリクエストを送信します。返される応答は301 Moved Permanentlyになります。
次に、extract the Location headerが次の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 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 –は実際には2回短縮されます– 1回目はbit.ly経由、2回目は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を使用する方法について説明しました。
1回だけ短縮されたURLを使用した単純なユースケースから始めて、プロセスの複数レベルのリダイレクトを処理し、リダイレクトループを検出できる、より一般的なメカニズムを実装しました。
これらの例の実装はthe github projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。