java - 无法从返回重定向的 URL 下载文件
问题描述
我正在尝试将一组文件从远程服务器下载到本地文件。
这应该很简单,我尝试了 2 种不同的方法,但每种方法都有利有弊。
第一种方法 - Apache HttpGet/CloseableHttpResponse
CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
URL encodeUrl = new URL(UriUtils.encodePath(documentUrl, StandardCharsets.UTF_8.name()));
File file = new File(tmpdir + File.separator + FilenameUtils.getName(doc.getDocumentURL()));
HttpGet httpget = new HttpGet(encodeUrl.toString());
HttpEntity entity = null;
try(CloseableHttpResponse response = closeableHttpClient.execute(httpget) {
entity = response.getEntity();
FileUtils.copyInputStreamToFile(entity.getContent(), file);
} finally {
EntityUtils.consumeQuietly(entity);
}
第二种方法 - FileUtils.copyURLToFile
URL encodeUrl = new URL(UriUtils.encodePath(documentUrl, StandardCharsets.UTF_8.name()));
String filename = FilenameUtils.getName(documentUrl);
File file = new File(tmpdir + File.separator + filename);
FileUtils.copyURLToFile(encodeUrl, file, 10000, 30000);
我对这两种方法都有问题。
1. 使用 Apache HttpGet/CloseableHttpResponse:
某些 URL 的名称中有空格甚至奇怪的字符,例如:
http://download-service/Document Number 2015 .pdf
所有名称正确的文件都已正确下载,但名称不正确的文件出现此错误:
org.apache.http.client.ClientProtocolException: null
...
Caused by: org.apache.http.ProtocolException: Invalid redirect URI: http://download-service/Document Number 2015 .pdf
at org.apache.http.impl.client.DefaultRedirectStrategy.createLocationURI(DefaultRedirectStrategy.java:200) ~[httpclient-4.5.5.jar:4.5.5]
at org.apache.http.impl.client.DefaultRedirectStrategy.getLocationURI(DefaultRedirectStrategy.java:148) ~[httpclient-4.5.5.jar:4.5.5]
at org.apache.http.impl.client.DefaultRedirectStrategy.getRedirect(DefaultRedirectStrategy.java:221) ~[httpclient-4.5.5.jar:4.5.5]
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:122) ~[httpclient-4.5.5.jar:4.5.5]
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[httpclient-4.5.5.jar:4.5.5]
... 108 common frames omitted
Caused by: java.net.URISyntaxException: Illegal character in path at index 48: http://download-service/Document Number 2015 .pdf
at java.net.URI$Parser.fail(URI.java:2848) ~[na:1.8.0_131]
at java.net.URI$Parser.checkChars(URI.java:3021) ~[na:1.8.0_131]
at java.net.URI$Parser.parseHierarchical(URI.java:3105) ~[na:1.8.0_131]
at java.net.URI$Parser.parse(URI.java:3053) ~[na:1.8.0_131]
at java.net.URI.<init>(URI.java:588) ~[na:1.8.0_131]
at org.apache.http.impl.client.DefaultRedirectStrategy.createLocationURI(DefaultRedirectStrategy.java:189) ~[httpclient-4.5.5.jar:4.5.5]
... 112 common frames omitted
2. 使用 FileUtils.copyURLToFile:
在这种情况下,不会发生上述错误,所有文件似乎都已正确下载,但所有文件都是空的。
我已经阅读了这两种方法的文档,但我无法理解这两种方法的失败之处。
解决方案
我研究了以下错误,并开始怀疑该问题可能与服务器执行的重定向有关:
Caused by: org.apache.http.ProtocolException: Invalid redirect URI:
因此,我创建了一个 CustomRedirectStrategy,它将在重定向上执行 URI 编码:
public class CustomRedirectStrategy extends DefaultRedirectStrategy {
@Override
public URI getLocationURI(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
try {
String uri = response.getFirstHeader("location").getValue();
URL url = new URL(uri);
return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
} catch (Exception ex){
throw new ProtocolException(ex.getMessage());
}
}
}
他们将这个策略应用于 CloseableHttpClient:
CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new CustomRedirectStrategy()).build();
通过此更改,所有文件现在都已正确下载。
推荐阅读
- docker-compose - 如何为 gitlab-runner CI 挂载/重用 docker-compose 机密?
- node.js - AWS SES 发送多个 PDF 附件 Nodejs
- python - 使用 Python Selenium Webdriver 自动导出 Azure Devops 管道工作项修订
- php - 如何比较数组值以检查正确答案
- firebase - 为什么反应原生地图功能无法正常工作?
- python - 如何使用正则表达式解析 PCI 地址?
- javascript - 如何替换字符串中的 [object HTMLDivElement]?
- python - 如何在 Mac 上的 Colab 下从 Anaconda 内部安装“plotly”
- python - 如何使用 python web 抓取从主页获取所有列表 url
- javascript - 如何在 AngularJS 的多个查询参数中设置特定参数?