HttpClient перенаправляет 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;
                }
        }

Ответ 3

Другой пример рабочего кода, который заменит пробелы на %20 на основе fooobar.com/questions/25616/...

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));
        // /questions/25616/url-encoding-in-android/186948#186948
        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;
}

Ответ 5

Я рекомендую создать настраиваемую стратегию перенаправления

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

который вы можете установить в своем клиенте с помощью метода setRedirectStrategy.

HttpAsyncClients.custom.setRedirectStrategy(new CustomRedirectStrategy).build