Java HttpClient 4 - 如何捕获上次重定向 URL
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1456987/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HttpClient 4 - how to capture last redirect URL
提问by Bostone
I have rather simple HttpClient 4 code that calls HttpGet to get HTML output. The HTML returns with scripts and image locations all set to local (e.g. <img src="/images/foo.jpg"/>
) so I need calling URL to make these into absolute (<img src="http://foo.com/images/foo.jpg"/>
) Now comes the problem - during the call there may be one or two 302 redirects so the original URL is no longer reflects the location of HTML.
我有相当简单的 HttpClient 4 代码,它调用 HttpGet 来获取 HTML 输出。HTML 返回的脚本和图像位置都设置为本地(例如<img src="/images/foo.jpg"/>
),所以我需要调用 URL 使它们成为绝对的(<img src="http://foo.com/images/foo.jpg"/>
) 现在问题来了 - 在调用过程中可能会有一两个 302 重定向,因此原始 URL 不再是反映了 HTML 的位置。
How do I get the latest URL of the returned content given all the redirects I may (or may not) have?
考虑到我可能(或可能没有)拥有的所有重定向,如何获取返回内容的最新 URL?
I looked at HttpGet#getAllHeaders()
and HttpResponse#getAllHeaders()
- couldn't find anything.
我看着HttpGet#getAllHeaders()
和HttpResponse#getAllHeaders()
-找不到任何东西。
Edited: HttpGet#getURI()
returns original calling address
编辑:HttpGet#getURI()
返回原始调用地址
采纳答案by ZZ Coder
That would be the current URL, which you can get by calling
那将是当前的 URL,您可以通过调用获得
HttpGet#getURI();
EDIT: You didn't mention how you are doing redirect. That works for us because we handle the 302 ourselves.
编辑:您没有提到您如何进行重定向。这对我们有用,因为我们自己处理 302。
Sounds like you are using DefaultRedirectHandler. We used to do that. It's kind of tricky to get the current URL. You need to use your own context. Here are the relevant code snippets,
听起来您正在使用 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());
The default redirect didn't work for us so we changed but I forgot what was the problem.
默认重定向对我们不起作用,所以我们进行了更改,但我忘记了问题所在。
回答by Nikola
In version 2.3 Android still do not support following redirect (HTTP code 302). I just read location header and download again:
在 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;
}
}
No circular redirects protection here so be careful. More on by blog Follow 302 redirects with AndroidHttpClient
这里没有循环重定向保护,所以要小心。博客中的更多信息使用 AndroidHttpClient 跟踪 302 重定向
回答by ydanila
I think easier way to find last URL is to use DefaultRedirectHandler.
我认为查找最后一个 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;
}
}
Code to use this handler:
使用此处理程序的代码:
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();
}
回答by Michael Pollmeier
An IMHO improved way based upon ZZ Coder's solution is to use a ResponseInterceptor to simply track the last redirect location. That way you don't lose information e.g. after an hashtag. Without the response interceptor you lose the hashtag. Example: http://j.mp/OxbI23
恕我直言,基于 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";
use it just like ZZ Coder's solution:
就像 ZZ Coder 的解决方案一样使用它:
HttpResponse response = httpClient.execute(httpGet, context);
String url = getUrlAfterRedirects(context);
回答by Salman
This is how I managed to get the redirect URL:
这就是我设法获取重定向 URL 的方式:
Header[] arr = httpResponse.getHeaders("Location");
for (Header head : arr){
String whatever = arr.getValue();
}
Or, if you are sure that there is only one redirect location, do this:
或者,如果您确定只有一个重定向位置,请执行以下操作:
httpResponse.getFirstHeader("Location").getValue();
回答by david_p
In HttpClient 4, if you are using LaxRedirectStrategy
or any subclass of DefaultRedirectStrategy
, this is the recommended way (see source code of DefaultRedirectStrategy
) :
在 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);
}
Since HttpClient 4.3.x, the above code can be simplified as:
从 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);
}
回答by Atharva
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);
}
回答by AmirHossein
I found this on HttpComponents Client Documentation
我在HttpComponents Client Documentation上找到了这个
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();
}