httpclient 4 - كيفية التقاط عنوان URL آخر إعادة توجيه

StackOverflow https://stackoverflow.com/questions/1456987

  •  12-09-2019
  •  | 
  •  

سؤال

لدي رمز HTTPClient بسيطة إلى حد ما الذي يستدعي شاشة التلفزيون للحصول على إخراج 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() إرجاع عنوان الاتصال الأصلي

هل كانت مفيدة؟

المحلول

سيكون ذلك هو عنوان URL الحالي الذي يمكنك الحصول عليه عن طريق الاتصال به

  HttpGet#getURI();

تحرير: لم تذكر كيف تقوم بإعادة توجيه. الذي يعمل لنا لأننا نتعامل مع 302 أنفسنا.

يبدو أنك تستخدم defaultredirecthrectherler. اعتدنا أن نفعل ذلك. إنه نوع من الصعب للحصول على عنوان 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());

لم ينجح إعادة التوجيه الافتراضي بالنسبة لنا لذلك غيرنا ولكن نسيت ما كانت المشكلة.

نصائح أخرى

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

تتمثل طريقة محسنة IMHO بناء على حل ZZ Coder في استخدام ردايونالإعبرة لتتبع موقع إعادة توجيه الماضي. بهذه الطريقة لا تفقد المعلومات على سبيل المثال بعد علامة التجزئة. بدون اعتراض الاستجابة تفقد علامة التجزئة. مثال: 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);

لقد وجدت هذا على وثائق عميل httpCommonents

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

أعتقد أن طريقة أسهل للعثور على عنوان URL الأخير هو استخدام defaultredirecthrectherler.

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

لا توجد حماية دائرية الحماية هنا حتى تكون حذرا. المزيد عنها بلوق اتبع 152 يعيد توجيهات مع AndroidHTTPClient

هذه هي الطريقة التي تمكنت من الحصول على عنوان URL إعادة توجيه:

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

أو، إذا كنت متأكدا من وجود موقع إعادة توجيه واحد فقط، فقم بذلك:

httpResponse.getFirstHeader("Location").getValue();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top