HttpClient 4 - как перехватить последний URL перенаправления - PullRequest
50 голосов
/ 22 сентября 2009

У меня довольно простой код HttpClient 4, который вызывает HttpGet для получения вывода HTML. HTML возвращается со сценариями и местоположениями изображений, которые установлены на локальные (например, <img src="/images/foo.jpg"/>), поэтому мне нужно вызвать URL, чтобы сделать их абсолютными (<img src="http://foo.com/images/foo.jpg"/>). Теперь возникает проблема - во время вызова может быть один или два перенаправления 302 исходный URL больше не отражает местоположение HTML.

Как получить последний URL возвращенного контента с учетом всех перенаправлений, которые я могу (или не могу) иметь?

Я посмотрел на HttpGet#getAllHeaders() и HttpResponse#getAllHeaders() - ничего не смог найти.

Отредактировано: HttpGet#getURI() возвращает исходный вызывающий адрес

Ответы [ 8 ]

63 голосов
/ 22 сентября 2009

Это будет текущий URL, который вы можете получить, позвонив по номеру

  HttpGet#getURI();

РЕДАКТИРОВАТЬ: Вы не упомянули, как вы делаете перенаправление. Это работает для нас, потому что мы сами обращаемся с 302.

Похоже, вы используете 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());

Перенаправление по умолчанию у нас не работает, поэтому мы изменились, но я забыл, в чем проблема.

36 голосов
/ 11 декабря 2013

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

Поскольку 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);
}
10 голосов
/ 03 мая 2014
    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);
    }
5 голосов
/ 25 июля 2012

IMHO улучшенный способ, основанный на решении 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";

используйте его так же, как решение ZZ Coder:

HttpResponse response = httpClient.execute(httpGet, context);
String url = getUrlAfterRedirects(context);
4 голосов
/ 23 января 2016

Я нашел это в Документация клиента HttpComponents

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();
}
4 голосов
/ 23 апреля 2012

Я думаю, что более простой способ найти последний 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;
    }

}

Код для использования этого обработчика:

  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();
  }
2 голосов
/ 27 января 2011

В версии 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;
    }
}

Здесь нет круговой защиты от перенаправлений, поэтому будьте осторожны. Подробнее в блоге Следите за 302 перенаправлениями с AndroidHttpClient

0 голосов
/ 02 июля 2013

Вот так мне удалось получить URL перенаправления:

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

Или, если вы уверены, что существует только одно место перенаправления, сделайте следующее:

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