Java HttpClient 4 - 如何捕获上次重定向 URL

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1456987/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:28:11  来源:igfitidea点击:

HttpClient 4 - how to capture last redirect URL

javaapache-httpclient-4.x

提问by Bostone

I have rather simple HttpClient 4 code that calls HttpGet to get HTML output. The HTML returns with scripts and image locations all set to local (e.g. <img src="/images/foo.jpg"/>) so I need calling URL to make these into absolute (<img src="http://foo.com/images/foo.jpg"/>) Now comes the problem - during the call there may be one or two 302 redirects so the original URL is no longer reflects the location of HTML.

我有相当简单的 HttpClient 4 代码,它调用 HttpGet 来获取 HTML 输出。HTML 返回的脚本和图像位置都设置为本地(例如<img src="/images/foo.jpg"/>),所以我需要调用 URL 使它们成为绝对的(<img src="http://foo.com/images/foo.jpg"/>) 现在问题来了 - 在调用过程中可能会有一两个 302 重定向,因此原始 URL 不再是反映了 HTML 的位置。

How do I get the latest URL of the returned content given all the redirects I may (or may not) have?

考虑到我可能(或可能没有)拥有的所有重定向,如何获取返回内容的最新 URL?

I looked at HttpGet#getAllHeaders()and HttpResponse#getAllHeaders()- couldn't find anything.

我看着HttpGet#getAllHeaders()HttpResponse#getAllHeaders()-找不到任何东西。

Edited: HttpGet#getURI()returns original calling address

编辑:HttpGet#getURI()返回原始调用地址

采纳答案by ZZ Coder

That would be the current URL, which you can get by calling

那将是当前的 URL,您可以通过调用获得

  HttpGet#getURI();

EDIT: You didn't mention how you are doing redirect. That works for us because we handle the 302 ourselves.

编辑:您没有提到您如何进行重定向。这对我们有用,因为我们自己处理 302。

Sounds like you are using DefaultRedirectHandler. We used to do that. It's kind of tricky to get the current URL. You need to use your own context. Here are the relevant code snippets,

听起来您正在使用 DefaultRedirectHandler。我们曾经这样做过。获取当前 URL 有点棘手。您需要使用自己的上下文。这是相关的代码片段,

        HttpGet httpget = new HttpGet(url);
        HttpContext context = new BasicHttpContext(); 
        HttpResponse response = httpClient.execute(httpget, context); 
        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
            throw new IOException(response.getStatusLine().toString());
        HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute( 
                ExecutionContext.HTTP_REQUEST);
        HttpHost currentHost = (HttpHost)  context.getAttribute( 
                ExecutionContext.HTTP_TARGET_HOST);
        String currentUrl = (currentReq.getURI().isAbsolute()) ? currentReq.getURI().toString() : (currentHost.toURI() + currentReq.getURI());

The default redirect didn't work for us so we changed but I forgot what was the problem.

默认重定向对我们不起作用,所以我们进行了更改,但我忘记了问题所在。

回答by Nikola

In version 2.3 Android still do not support following redirect (HTTP code 302). I just read location header and download again:

在 2.3 版本中,Android 仍然不支持以下重定向(HTTP 代码 302)。我只是阅读了位置标题并再次下载:

if (statusCode != HttpStatus.SC_OK) {
    Header[] headers = response.getHeaders("Location");

    if (headers != null && headers.length != 0) {
        String newUrl = headers[headers.length - 1].getValue();
        // call again the same downloading method with new URL
        return downloadBitmap(newUrl);
    } else {
        return null;
    }
}

No circular redirects protection here so be careful. More on by blog Follow 302 redirects with AndroidHttpClient

这里没有循环重定向保护,所以要小心。博客中的更多信息使用 AndroidHttpClient 跟踪 302 重定向

回答by ydanila

I think easier way to find last URL is to use DefaultRedirectHandler.

我认为查找最后一个 URL 的更简单方法是使用 DefaultRedirectHandler。

package ru.test.test;

import java.net.URI;

import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.impl.client.DefaultRedirectHandler;
import org.apache.http.protocol.HttpContext;

public class MyRedirectHandler extends DefaultRedirectHandler {

    public URI lastRedirectedUri;

    @Override
    public boolean isRedirectRequested(HttpResponse response, HttpContext context) {

        return super.isRedirectRequested(response, context);
    }

    @Override
    public URI getLocationURI(HttpResponse response, HttpContext context)
            throws ProtocolException {

        lastRedirectedUri = super.getLocationURI(response, context);

        return lastRedirectedUri;
    }

}

Code to use this handler:

使用此处理程序的代码:

  DefaultHttpClient httpclient = new DefaultHttpClient();
  MyRedirectHandler handler = new MyRedirectHandler();
  httpclient.setRedirectHandler(handler);

  HttpGet get = new HttpGet(url);

  HttpResponse response = httpclient.execute(get);

  HttpEntity entity = response.getEntity();
  lastUrl = url;
  if(handler.lastRedirectedUri != null){
      lastUrl = handler.lastRedirectedUri.toString();
  }

回答by Michael Pollmeier

An IMHO improved way based upon ZZ Coder's solution is to use a ResponseInterceptor to simply track the last redirect location. That way you don't lose information e.g. after an hashtag. Without the response interceptor you lose the hashtag. Example: http://j.mp/OxbI23

恕我直言,基于 ZZ Coder 解决方案的改进方法是使用 ResponseInterceptor 来简单地跟踪最后一个重定向位置。这样你就不会丢失信息,例如在标签之后。如果没有响应拦截器,您将丢失主题标签。示例:http: //j.mp/OxbI23

private static HttpClient createHttpClient() throws NoSuchAlgorithmException, KeyManagementException {
    SSLContext sslContext = SSLContext.getInstance("SSL");
    TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllTrustManager() };
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslContext);
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("https", 443, sslSocketFactory));
    schemeRegistry.register(new Scheme("http", 80, new PlainSocketFactory()));

    HttpParams params = new BasicHttpParams();
    ClientConnectionManager cm = new org.apache.http.impl.conn.SingleClientConnManager(schemeRegistry);

    // some pages require a user agent
    AbstractHttpClient httpClient = new DefaultHttpClient(cm, params);
    HttpProtocolParams.setUserAgent(httpClient.getParams(), "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0.1");

    httpClient.setRedirectStrategy(new RedirectStrategy());

    httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
        @Override
        public void process(HttpResponse response, HttpContext context)
                throws HttpException, IOException {
            if (response.containsHeader("Location")) {
                Header[] locations = response.getHeaders("Location");
                if (locations.length > 0)
                    context.setAttribute(LAST_REDIRECT_URL, locations[0].getValue());
            }
        }
    });

    return httpClient;
}

private String getUrlAfterRedirects(HttpContext context) {
    String lastRedirectUrl = (String) context.getAttribute(LAST_REDIRECT_URL);
    if (lastRedirectUrl != null)
        return lastRedirectUrl;
    else {
        HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
        HttpHost currentHost = (HttpHost)  context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
        String currentUrl = (currentReq.getURI().isAbsolute()) ? currentReq.getURI().toString() : (currentHost.toURI() + currentReq.getURI());
        return currentUrl;
    }
}

public static final String LAST_REDIRECT_URL = "last_redirect_url";

use it just like ZZ Coder's solution:

就像 ZZ Coder 的解决方案一样使用它:

HttpResponse response = httpClient.execute(httpGet, context);
String url = getUrlAfterRedirects(context);

回答by Salman

This is how I managed to get the redirect URL:

这就是我设法获取重定向 URL 的方式:

Header[] arr = httpResponse.getHeaders("Location");
for (Header head : arr){
    String whatever = arr.getValue();
}

Or, if you are sure that there is only one redirect location, do this:

或者,如果您确定只有一个重定向位置,请执行以下操作:

httpResponse.getFirstHeader("Location").getValue();

回答by david_p

In HttpClient 4, if you are using LaxRedirectStrategyor any subclass of DefaultRedirectStrategy, this is the recommended way (see source code of DefaultRedirectStrategy) :

在 HttpClient 4 中,如果您正在使用LaxRedirectStrategy或 的任何子类DefaultRedirectStrategy,这是推荐的方式(请参阅 的源代码DefaultRedirectStrategy):

HttpContext context = new BasicHttpContext();
HttpResult<T> result = client.execute(request, handler, context);
URI finalUrl = request.getURI();
RedirectLocations locations = (RedirectLocations) context.getAttribute(DefaultRedirectStrategy.REDIRECT_LOCATIONS);
if (locations != null) {
    finalUrl = locations.getAll().get(locations.getAll().size() - 1);
}

Since HttpClient 4.3.x, the above code can be simplified as:

从 HttpClient 4.3.x 开始,上面的代码可以简化为:

HttpClientContext context = HttpClientContext.create();
HttpResult<T> result = client.execute(request, handler, context);
URI finalUrl = request.getURI();
List<URI> locations = context.getRedirectLocations();
if (locations != null) {
    finalUrl = locations.get(locations.size() - 1);
}

回答by Atharva

    HttpGet httpGet = new HttpHead("<put your URL here>");
    HttpClient httpClient = HttpClients.createDefault();
    HttpClientContext context = HttpClientContext.create();
    httpClient.execute(httpGet, context);
    List<URI> redirectURIs = context.getRedirectLocations();
    if (redirectURIs != null && !redirectURIs.isEmpty()) {
        for (URI redirectURI : redirectURIs) {
            System.out.println("Redirect URI: " + redirectURI);
        }
        URI finalURI = redirectURIs.get(redirectURIs.size() - 1);
    }

回答by AmirHossein

I found this on HttpComponents Client Documentation

我在HttpComponents Client Documentation上找到了这个

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("http://localhost:8080/");
CloseableHttpResponse response = httpclient.execute(httpget, context);
try {
    HttpHost target = context.getTargetHost();
    List<URI> redirectLocations = context.getRedirectLocations();
    URI location = URIUtils.resolve(httpget.getURI(), target, redirectLocations);
    System.out.println("Final HTTP location: " + location.toASCIIString());
    // Expected to be an absolute URI
} finally {
    response.close();
}