java HttpClient 重定向到带有空格的 URL 抛出异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3420767/
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 redirecting to URL with spaces throwing exception
提问by Aymon Fournier
I am accessing a URL that's redirecting me to a URL with spaces in it. (Using HttpClient 4.x) How do I prevent this from throwing an error (replacing the spaces with %20 not +)
我正在访问一个 URL,该 URL 将我重定向到一个包含空格的 URL。(使用 HttpClient 4.x)如何防止抛出错误(用 %20 而不是 + 替换空格)
08-06 02:45:56.486: WARN/System.err(655): org.apache.http.client.ClientProtocolException
08-06 02:45:56.493: WARN/System.err(655): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:557)
08-06 02:45:56.534: WARN/System.err(655): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:509)
08-06 02:45:56.603: WARN/System.err(655): at com.romcessed.romsearch.searchproviders.DopeRomsConnector$DownloadROMTask.doInBackground(DopeRomsConnector.java:636)
08-06 02:45:56.623: WARN/System.err(655): at com.romcessed.romsearch.searchproviders.DopeRomsConnector$DownloadROMTask.doInBackground(DopeRomsConnector.java:1)
08-06 02:45:56.643: WARN/System.err(655): at android.os.AsyncTask.call(AsyncTask.java:185)
08-06 02:45:56.663: WARN/System.err(655): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
08-06 02:45:56.683: WARN/System.err(655): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
08-06 02:45:56.693: WARN/System.err(655): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
08-06 02:45:56.713: WARN/System.err(655): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
08-06 02:45:56.713: WARN/System.err(655): at java.lang.Thread.run(Thread.java:1096)
08-06 02:45:56.743: WARN/System.err(655): Caused by: org.apache.http.ProtocolException: Invalid redirect URI: http://somewebsite.com/some file with spaces.zip
08-06 02:45:56.787: WARN/System.err(655): at org.apache.http.impl.client.DefaultRedirectHandler.getLocationURI(DefaultRedirectHandler.java:116)
08-06 02:45:56.803: WARN/System.err(655): at org.apache.http.impl.client.DefaultRequestDirector.handleResponse(DefaultRequestDirector.java:892)
08-06 02:45:56.813: WARN/System.err(655): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:457)
08-06 02:45:56.843: WARN/System.err(655): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
08-06 02:45:56.843: WARN/System.err(655): ... 9 more
08-06 02:45:56.873: WARN/System.err(655): Caused by: java.net.URISyntaxException: Illegal character in path at index #: http://somewebsite.com/some file with spaces.zip
08-06 02:45:56.913: WARN/System.err(655): at java.net.URI$Helper.validatePath(URI.java:448)
08-06 02:45:56.923: WARN/System.err(655): at java.net.URI$Helper.parseURI(URI.java:398)
08-06 02:45:56.953: WARN/System.err(655): at java.net.URI$Helper.access0(URI.java:302)
08-06 02:45:56.963: WARN/System.err(655): at java.net.URI.<init>(URI.java:87)
08-06 02:45:56.993: WARN/System.err(655): at org.apache.http.impl.client.DefaultRedirectHandler.getLocationURI(DefaultRedirectHandler.java:114)
08-06 02:45:57.013: WARN/System.err(655): ... 12 more
回答by Trevor Johns
The Apache HTTP library allows you to register a RedirectHandler object that will get invoked whenever a redirect occurs. You can use this to intercept the redirect and fix it.
Apache HTTP 库允许您注册一个 RedirectHandler 对象,该对象将在发生重定向时被调用。您可以使用它来拦截重定向并修复它。
(That being said, the site that's sending you this redirect is broken. You should contact them and let them know.)
(话虽如此,向您发送此重定向的站点已损坏。您应该与他们联系并让他们知道。)
class CustomRedirectHandler extends DefaultRedirectHandler {
public URI getLocationURI(HttpResponse response, HttpContext context) {
// Extract the Location: header and manually convert spaces to %20's
// Return the corrected URI
}
}
DefaultHttpClient httpClient = new DefaultHttpClient();
RedirectHandler customRedirectHandler = new CustomRedirectHandler();
//...
httpClient.setRedirectHandler(customRedirectHandler);
回答by Aymon Fournier
Here is my working code :)
这是我的工作代码:)
class spaceRedirectHandler extends DefaultRedirectHandler{
private static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
public spaceRedirectHandler() {
super();
}
public boolean isRedirectRequested(
final HttpResponse response,
final HttpContext context) {
if (response == null) {
throw new IllegalArgumentException("HTTP response may not be null");
}
int statusCode = response.getStatusLine().getStatusCode();
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY:
case HttpStatus.SC_MOVED_PERMANENTLY:
case HttpStatus.SC_SEE_OTHER:
case HttpStatus.SC_TEMPORARY_REDIRECT:
return true;
default:
return false;
} //end of switch
}
public URI getLocationURI(
final HttpResponse response,
final HttpContext context) throws ProtocolException {
if (response == null) {
throw new IllegalArgumentException("HTTP response may not be null");
}
//get the location header to find out where to redirect to
Header locationHeader = response.getFirstHeader("location");
if (locationHeader == null) {
// got a redirect response, but no location header
throw new ProtocolException(
"Received redirect response " + response.getStatusLine()
+ " but no location header");
}
//HERE IS THE MODIFIED LINE OF CODE
String location = locationHeader.getValue().replaceAll (" ", "%20");
URI uri;
try {
uri = new URI(location);
} catch (URISyntaxException ex) {
throw new ProtocolException("Invalid redirect URI: " + location, ex);
}
HttpParams params = response.getParams();
// rfc2616 demands the location value be a complete URI
// Location = "Location" ":" absoluteURI
if (!uri.isAbsolute()) {
if (params.isParameterTrue(ClientPNames.REJECT_RELATIVE_REDIRECT)) {
throw new ProtocolException("Relative redirect location '"
+ uri + "' not allowed");
}
// Adjust location URI
HttpHost target = (HttpHost) context.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
if (target == null) {
throw new IllegalStateException("Target host not available " +
"in the HTTP context");
}
HttpRequest request = (HttpRequest) context.getAttribute(
ExecutionContext.HTTP_REQUEST);
try {
URI requestURI = new URI(request.getRequestLine().getUri());
URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target, true);
uri = URIUtils.resolve(absoluteRequestURI, uri);
} catch (URISyntaxException ex) {
throw new ProtocolException(ex.getMessage(), ex);
}
}
if (params.isParameterFalse(ClientPNames.ALLOW_CIRCULAR_REDIRECTS)) {
RedirectLocations redirectLocations = (RedirectLocations) context.getAttribute(
REDIRECT_LOCATIONS);
if (redirectLocations == null) {
redirectLocations = new RedirectLocations();
context.setAttribute(REDIRECT_LOCATIONS, redirectLocations);
}
URI redirectURI;
if (uri.getFragment() != null) {
try {
HttpHost target = new HttpHost(
uri.getHost(),
uri.getPort(),
uri.getScheme());
redirectURI = URIUtils.rewriteURI(uri, target, true);
} catch (URISyntaxException ex) {
throw new ProtocolException(ex.getMessage(), ex);
}
} else {
redirectURI = uri;
}
if (redirectLocations.contains(redirectURI)) {
throw new CircularRedirectException("Circular redirect to '" +
redirectURI + "'");
} else {
redirectLocations.add(redirectURI);
}
}
return uri;
}
}
回答by expert
I recommend creating custom redirect strategy
我建议创建自定义重定向策略
class CustomRedirectStrategy extends DefaultRedirectStrategy {
// NOTE: Hack for bad redirects such as: http://www.healio.com/Rss/Allergy%20Immunology
override def createLocationURI(location: String): URI = {
try {
super.createLocationURI(location)
} catch {
case ex: ProtocolException =>
val url = new URL(location)
val uri = new URI(url.getProtocol, url.getUserInfo, url.getHost, url.getPort, url.getPath, url.getQuery, url.getRef)
uri
}
}
}
that you can set in your client via setRedirectStrategymethod.
您可以通过setRedirectStrategy方法在客户端中设置。
HttpAsyncClients.custom.setRedirectStrategy(new CustomRedirectStrategy).build
回答by Jakob Eriksson
Another working code example that will replace spaces with %20, based on https://stackoverflow.com/a/8962879/956415
另一个使用 %20 替换空格的工作代码示例,基于https://stackoverflow.com/a/8962879/956415
private download(){
...
mHttpClient = new DefaultHttpClient(httpParams);
mHttpClient.setRedirectHandler(new DefaultRedirectHandler() {
@Override
public boolean isRedirectRequested(HttpResponse httpResponse, HttpContext httpContext) {
return super.isRedirectRequested(httpResponse, httpContext);
}
@Override
public URI getLocationURI(HttpResponse httpResponse, HttpContext httpContext) throws ProtocolException {
return sanitizeUrl(httpResponse.getFirstHeader("location").getValue());
}
});
}
private URI sanitizeUrl(String sanitizeURL) throws ProtocolException {
URI uri = null;
try {
URL url = new URL(URLDecoder.decode(sanitizeURL, UTF_8));
// https://stackoverflow.com/a/8962879/956415
uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
} catch (URISyntaxException | MalformedURLException | UnsupportedEncodingException e) {
throw new ProtocolException(e.getMessage(), e);
}
return uri;
}
回答by Aaron Saunders
http://download.oracle.com/javase/6/docs/api/java/net/URI.html
http://download.oracle.com/javase/6/docs/api/java/net/URI.html
or just replace the "+" with the %20
或者只是用 %20 替换“+”
similar question
类似的问题

