Подтвердить что ты не робот

HttpClient 4 - как захватить последний URL переадресации

У меня довольно простой код 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() возвращает исходный адрес вызова

4b9b3361

Ответ 1

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

  HttpGet#getURI();

EDIT: Вы не упомянули, как вы делаете перенаправление. Это работает для нас, потому что мы сами обрабатываем 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());

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

Ответ 2

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

Ответ 3

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

Ответ 4

Улучшенный способ 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);

Ответ 5

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

Ответ 6

Я нашел это на Документация клиента 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();
}

Ответ 7

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

Ответ 8

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

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

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

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