web-dev-qa-db-fra.com

HttpClient 4 - comment capturer la dernière URL de redirection

J'ai un code HttpClient 4 assez simple qui appelle HttpGet pour obtenir une sortie HTML. Le code HTML revient avec des scripts et des emplacements d'images tous définis en local (par exemple <img src="/images/foo.jpg"/>). J'ai donc besoin d'appeler l'URL pour les transformer en absolus (<img src="http://foo.com/images/foo.jpg"/>). Maintenant vient le problème - pendant l'appel, il peut y avoir une ou deux redirections 302 afin que l'URL d'origine ne reflète plus l'emplacement du HTML.

Comment puis-je obtenir la dernière URL du contenu renvoyé compte tenu de toutes les redirections que je peux (ou pas) avoir?

J'ai regardé HttpGet#getAllHeaders() et HttpResponse#getAllHeaders() - je n'ai rien trouvé.

Modifié: HttpGet#getURI() renvoie l'adresse d'appel d'origine

50
Bostone

Ce serait l'URL actuelle, que vous pouvez obtenir en appelant

  HttpGet#getURI();

EDIT: Vous n'avez pas mentionné comment vous faites la redirection. Cela fonctionne pour nous car nous gérons nous-mêmes le 302.

On dirait que vous utilisez DefaultRedirectHandler. Nous le faisions. Il est assez difficile d'obtenir l'URL actuelle. Vous devez utiliser votre propre contexte. Voici les extraits de code pertinents,

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

La redirection par défaut ne fonctionnait pas pour nous, nous avons donc changé mais j'ai oublié quel était le problème.

63
ZZ Coder

Dans HttpClient 4, si vous utilisez LaxRedirectStrategy ou toute sous-classe de DefaultRedirectStrategy, c'est la méthode recommandée (voir le code source de 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);
}

Depuis HttpClient 4.3.x, le code ci-dessus peut être simplifié comme suit:

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);
}
37
david_p
    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);
    }
11
Atharva

Une manière améliorée à mon humble avis basée sur la solution de ZZ Coder consiste à utiliser un ResponseInterceptor pour simplement suivre le dernier emplacement de redirection. De cette façon, vous ne perdez pas d'informations, par exemple après un hashtag. Sans l'intercepteur de réponse, vous perdez le hashtag. Exemple: http://j.mp/OxbI2

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

utilisez-le comme la solution de ZZ Coder:

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

J'ai trouvé cela sur Documentation client 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();
}
5
AmirHossein

Je pense que le moyen le plus simple de trouver la dernière URL est d'utiliser 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 pour utiliser ce gestionnaire:

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

Dans la version 2.3 Android ne prend toujours pas en charge la redirection suivante (code HTTP 302). Je viens de lire l'en-tête de l'emplacement et de télécharger à nouveau:

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

Aucune protection contre les redirections circulaires ici, alors soyez prudent. Plus sur par blog Suivez les redirections 302 avec AndroidHttpClient

2
Nikola

Voici comment j'ai réussi à obtenir l'URL de redirection:

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

Ou, si vous êtes sûr qu'il n'y a qu'un seul emplacement de redirection, procédez comme suit:

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