2010-08-06 71 views
11

我正在訪問一個將我重定向到一個包含空格的URL的URL。 (使用HttpClient的4.x版)如何防止這種拋出一個錯誤(含20%+不更換空格)HttpClient重定向到URL,空格拋出異常

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 

回答

17

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

'setRedirectHandler'現在已被棄用,以支持'RedirectStrategy'。 – 2014-07-09 19:13:12

12

這是我工作的代碼:)

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

另一個工作代碼示例,將使用%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; 
} 
+0

我想,這個解決方案不適用於相對uri地址。 – Ales 2017-10-11 13:01:58

0

我建議創建自定義的重定向策略

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