leftso 1054 0 2018-04-06 21:22:24

文章位置:左搜> 编程技术> 正文

1.概述

在本文中,我们将演示如何使用 HttpClient 解除URL的绑定

一个简单的例子就是当原始URL被缩短一次 - 通过诸如bit.ly的服务。

一个更复杂的例子是,URL被多次缩短,被不同的服务缩短,并且需要多次才能到达原始的完整URL。

2.暂停URL一次

让我们从简单的开始 - 取消暂停仅通过一次缩短的URL服务传递的URL。

首先我们需要的是一个不会自动遵循重定向的http客户端:

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

这是必要的,因为我们需要手动拦截重定向响应并从中提取信息。

我们首先发送一个请求到缩短的网址 - 我们得到的回应将是一个301永久移动

然后,我们需要提取指向下一个位置标题,在这种情况下 - 最终的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级别

短网址的问题在于,它们可能会被完全不同的服务缩短多次。展开这样的网址需要多次传递才能访问原始网址。

我们将应用先前定义的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 void givenShortenedMultiple_whenUrlIsUnshortened_thenCorrectResult() throws IOException {
    String expectedResult = "/rest-versioning";
    String actualResult = expand("http://t.co/e4rDDbnzmk");
    assertThat(actualResult, equalTo(expectedResult));
}
这一次,短网址 - http://t.co/e4rDDbnzmk - 实际上缩短了两次 - 一次通过bit.ly,第二次通过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,然后实现一个更通用的机制,能够处理多个重定向级别并检测流程中的重定向循环。