Android DownloadManager下载失败,出现未知的400错误(文件名包含空格?)

3
我正在开发一款Android应用程序,使用DownloadManager下载文件。它能够成功地下载某些文件(例如JPEG、MP3),但对于其他文件(例如PDF)则不成功。我不确定这是否与文件类型有关。我注册了一个BroadcastReceiver来帮助调试问题。在onReceive()回调中,我查询DownloadManager以查找失败的原因,但它只给出了一个“400”,这不是一个记录的原因。
以下是我如何使用DownloadManager:
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(url);
request.setTitle(filename);
request.setDestinationInExternalPublicDir(folder, filename);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
manager.enqueue(request);

在DownloadManager.STATUS_FAILED状态下,这是我的调试代码:
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
Cursor cursor = manager.query(query);
if(cursor.moveToFirst()){                    
    int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
    int reason = cursor.getInt(columnReason);
    Log.e("App", reason);
    // the value of reason is 400 which is not a valid DownloadManager.ERROR_*
}

理应的情况下,原因的值应该是DownloadManager.ERROR_*中的一个常量,但400不是。在Galaxy Nexus (v4.3)和Nexus 9 (v5.1)这两个设备上发生了同样的事情。我在手机浏览器上测试了URL并确认它在应用程序之外可以工作。有人知道发生了什么吗?任何帮助都将不胜感激。
谢谢
编辑: 我试图下载的文件名中有一个空格。我进行了一些快速实验:从未起作用的文件中删除空格,向以前起作用的文件中添加空格。看起来可能与文件名包含空格有关。
编辑: 这是我解决问题的方法。我必须在服务器上对URL进行编码(URL是json响应的一部分,因此我更改了响应) url = URLEncoder.encode(url, "utf-8")

网站上的文件名称中从来不包含空格,这是有原因的。如果确实存在空格,网站应该尝试删除这些空格并使URI统一。这就是URL编码的含义! - JoxTraex
2个回答

4
这个400错误是HTTP错误。引用文档:
提供有关下载状态的更多详细信息。其含义取决于COLUMN_STATUS的值。当COLUMN_STATUS为STATUS_FAILED时,这表示发生的错误类型。如果发生HTTP错误,则将保留RFC 2616中定义的HTTP状态代码。否则,它将保留其中一个ERROR_*常量。[...]
参考链接:https://developer.android.com/reference/android/app/DownloadManager.html#COLUMN_REASON 而这个HTTP错误的意思是:
400错误请求 由于被视为客户端错误(例如,格式不正确的请求语法,无效的请求消息框架或欺骗性请求路由),服务器无法或不会处理请求。
如果您遇到其他HTTP错误,请查阅此页面以了解其含义:https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error

400错误似乎与HTTP错误代码对齐,但在这种情况下似乎没有意义,因为原因应始终在DownloadManager.ERROR_*范围内。在这种情况下,原因最多是ERROR_UNKOWN吗?我也进行了快速更新,文件名中有一个空格可能会导致问题。 - E.Yuen
“reason should be within the range of DownloadManget.ERROR_*”这种说法是不正确的,请查看文档:“如果发生了HTTP错误,它将保存在RFC 2616中定义的HTTP状态代码中。否则,它将保存在ERROR_*常量之一中。”-- https://developer.android.com/reference/android/app/DownloadManager.html#COLUMN_REASON - pelotasplus
刚刚编辑了帖子,包括相关文档部分和链接。 - pelotasplus
我在文档中漏掉了这点,谢谢提醒!原来是服务器没有对 Android 应用正在使用的路径进行 URL 编码。一旦我修复了服务器,应用程序就可以正常工作了。 - E.Yuen

0

通过这行代码,可以简单地删除URL中的空格:

url = url.replaceAll(" ", "%20");

当这个经过消毒的URL重定向到另一个带有空格的URL时,可能会发生奇怪的事情。例如请求:

GET http://example.com/file%20with%20spaces.pdf HTTP/1.1
Host: example.com

重定向的结果:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/new file with spaces.pdf

DownloadManager将遵循此重定向并对此未经过滤的URL进行请求:

GET http://example.com/new file with spaces.pdf HTTP/1.1
Host: example.com

这会导致400错误:

HTTP/1.0 400 Bad request: request protocol version denied

不幸的是,我发现唯一的解决方法是在您的代码中预先解析此重定向并清理第二个URL。


有没有办法获取重定向URL的文件名?我想使用默认文件名保存文件。 - user1788736

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接