我有一个相当简单的HttpClient 4代码,它调用HttpGet来获取HTML输出.HTML返回脚本和图像位置全部设置为本地(例如)所以我需要调用URL使这些成为绝对(
)现在出现问题 - 在调用期间可能有一个或两个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(); HttpResultresult = 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(); HttpResultresult = client.execute(request, handler, context); URI finalUrl = request.getURI(); List locations = context.getRedirectLocations(); if (locations != null) { finalUrl = locations.get(locations.size() - 1); }
HttpGet httpGet = new HttpHead(""); HttpClient httpClient = HttpClients.createDefault(); HttpClientContext context = HttpClientContext.create(); httpClient.execute(httpGet, context); List 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(); ListredirectLocations = 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(); }