Android DownloadManager 因无法识别的原因而失败 400(当文件名包含空格时?)

Android DownloadManager Fails with unrecognized reason 400 (when file name contains whitespace?)

我正在开发一个 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_*
}

reason 的值应该是常量之一 DownloadManager.ERROR_* 但 400 不是。同样的事情发生在两个设备上:Galaxy Nexus (v4.3) 和 Nexus 9 (v5.1)。我在 phone 的浏览器上测试了 URL 并确认它可以在应用程序之外工作。有谁知道发生了什么事?任何帮助将不胜感激。

谢谢

已编辑: 我要下载的文件的文件名中有一个 space。我做了一些快速实验:从不起作用的文件中删除 spaces,将 space 添加到以前起作用的文件中。看来它可能与包含 space.

的文件名有关

已编辑: 这就是我为解决问题所做的。我必须在服务器上对 URL 进行编码(URL 是 json 响应的一部分,所以我更改了响应)

url = URLEncoder.encode(url, "utf-8")

这个400的原因是HTTP错误。引用文档:

Provides more detail on the status of the download. Its meaning depends on the value of COLUMN_STATUS. When COLUMN_STATUS is STATUS_FAILED, this indicates the type of error that occurred. If an HTTP error occurred, this will hold the HTTP status code as defined in RFC 2616. Otherwise, it will hold one of the ERROR_* constants. [...]

https://developer.android.com/reference/android/app/DownloadManager.html#COLUMN_REASON

这个 HTTP 错误意味着

400 Bad Request The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

如果您遇到其他 HTTP 错误,请查阅此页面了解它们的含义:https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error

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

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

奇怪的是,当这个经过清理的 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

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