Pergunta

Eu tenho bastante simples código HttpClient 4 que chama HttpGet para obter HTML de saída. Os retornos HTML com scripts e locais de imagem tudo pronto para locais (por exemplo <img src="/images/foo.jpg"/>) Então eu preciso chamando URL para fazer isso em absoluto (<img src="http://foo.com/images/foo.jpg"/>) Agora vem o problema - durante a chamada pode haver um ou dois 302 redirecionamentos para que o URL original é já não reflecte a localização de HTML.

Como faço para receber as últimas URL do conteúdo retornado dado todos os redirecionamentos que podem (ou não podem) ter?

Eu olhei para HttpGet#getAllHeaders() e HttpResponse#getAllHeaders() - não consegui encontrar nada

.

Editado: HttpGet#getURI() retorna endereço chamado original

Foi útil?

Solução

Essa seria a URL atual, que você pode obter pelo telefone

  HttpGet#getURI();

EDIT: Você não mencionou como você está fazendo redirecionamento. Que funciona para nós, porque lidar com a 302 nós mesmos.

Parece que você está usando DefaultRedirectHandler. Nós costumávamos fazer isso. É uma espécie de complicado para obter a URL atual. Você precisa usar o seu próprio contexto. Aqui estão os trechos de código relevantes,

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

O redirecionamento padrão não funcionou para nós para que mudou, mas eu esqueci qual era o problema.

Outras dicas

Em HttpClient 4, se você estiver usando LaxRedirectStrategy ou qualquer subclasse de DefaultRedirectStrategy, esta é a maneira recomendada (ver código-fonte do 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);
}

Desde HttpClient 4.3.x, o código acima pode ser simplificada como:

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

Um IMHO melhorou maneira baseada na solução de ZZ Coder é usar um ResponseInterceptor simplesmente acompanhar o último local de redirecionamento. Dessa forma, você fazer informação não perdem por exemplo após uma hashtag. Sem o interceptor resposta você perde a hashtag. Exemplo: 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";

usá-lo apenas como solução de ZZ Coder:

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

Eu achei essa mensagem em HttpComponents Documentação do Cliente

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

Eu acho mais fácil maneira de encontrar última URL é usar 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;
    }

}

O código para usar esse manipulador:

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

Na versão 2.3 Android ainda não suportam seguinte redirecionamento HTTP (código 302). Acabei de ler cabeçalho de localização e download novamente:

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

Sem proteção redirecionamentos circulares aqui por isso tome cuidado. Mais sobre por blogue Siga 302 redirecionamentos com AndroidHttpClient

Isto é como eu consegui obter o URL de redirecionamento:

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

Ou, se tiver certeza de que há apenas um local de redirecionamento, faça o seguinte:

httpResponse.getFirstHeader("Location").getValue();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top