문제

HTML 출력을 얻기 위해 HttpGet을 호출하는 간단한 HttpClient 4 코드가 있습니다.HTML은 모두 로컬로 설정된 스크립트 및 이미지 위치와 함께 반환됩니다(예: <img src="/images/foo.jpg"/>) 따라서 이를 절대값으로 만들려면 URL을 호출해야 합니다(<img src="http://foo.com/images/foo.jpg"/>) 이제 문제가 발생합니다. 통화 중에 1~2개의 302 리디렉션이 있을 수 있으므로 원래 URL은 더 이상 HTML 위치를 반영하지 않습니다.

리디렉션이 있을 수도 있고 없을 수도 있는 모든 리디렉션을 고려하여 반환된 콘텐츠의 최신 URL을 어떻게 얻나요?

나는 보았다 HttpGet#getAllHeaders() 그리고 HttpResponse#getAllHeaders() - 아무것도 못 찾았어요.

편집됨: HttpGet#getURI() 원래 전화 주소를 반환합니다.

도움이 되었습니까?

해결책

이것이 현재 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());

기본 리디렉션이 작동하지 않아서 변경했지만 문제가 무엇인지 잊어버렸습니다.

다른 팁

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

ZZ Coder의 솔루션을 기반으로 하는 IMHO 개선 방법은 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);

나는 이것을 찾았다 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();
}

마지막 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.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;
    }
}

여기에는 순환 리디렉션 보호가 없으므로 주의하세요.자세한 내용은 블로그를 통해 확인하세요 AndroidHttpClient를 사용하여 302 리디렉션을 따릅니다.

이것이 내가 리디렉션 URL을 얻는 방법입니다.

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

또는 리디렉션 위치가 하나만 있다고 확신하는 경우 다음을 수행합니다.

httpResponse.getFirstHeader("Location").getValue();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top