HttpClient 重定向到带有空格引发异常的 URL

我正在访问一个 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$2.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.access$100(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

答案 1

Apache HTTP库允许您注册一个RedirectHandler对象,每当发生重定向时,该对象都会被调用。您可以使用它来拦截重定向并进行修复。

(话虽如此,向您发送此重定向的网站已损坏。您应该与他们联系并让他们知道。

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

答案 2

这是我的工作代码:)

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