iOS 上的 Safari 是否拒绝下载“application/octet-stream”内容?
Does Safari on iOS refuse to download `application/octet-stream` content?
我在 Node.js 中的标准 http
模块之上编写了一个 Web 服务器。它为我提供各种 HTML、JavaScript、CSS 和资产内容——自然而然地构成了我网页的大部分内容,这对我来说就像一个时钟。
当请求服务 URL 映射到具有未知扩展名的文件(没有进行 MIME 嗅探)时,它只是使用 header 的分块传输编码来提供内容Content-Type: application/octet-stream
,它也一直运行良好——我偶尔会在服务器上托管各种文件,并且能够在不受用户代理干扰的情况下下载这些文件,正如我对 application/octet-stream
的期望处理。
然而,今天,我尝试在 iOS 9.3.5 和 iPhone 4S 上的 Safari 移动浏览器 运行 下载,而那东西只是简单地拒绝从一个有效的 URL,提醒我:
Download failed. Safari cannot download this file.
我已经尝试添加 Content-Disposition: attachment
和 Content-Disposition: attachment; filename="foobar"
以取得更好的效果,但它仍然拒绝。
名为 random
的文件就是这种情况,其中填充了 1000 个随机字节。我的主机 header 是(Content-Disposition
是可选的,如上所述):
HTTP/1.1 200 OK
Host: example.com
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="foobar"
Date: Mon, 01 May 2017 13:48:37 GMT
Connection: keep-alive
Transfer-Encoding: chunked
根据记录,Android 6.x phone 也按预期运行(除了我的 Windows 10 x86_64 主机上的 Firefox 53),从 URL 顺利下载。
这里的 Safari 是怎么回事?
是的,您可以在 iOS 上使用 Safari 下载的唯一内容是图像。这是因为 iOS 不会向用户暴露文件结构(将文件下载到用户永远看不到的地方没有任何意义),它与防 Web 攻击无关。 Android 上的浏览器可以下载任意文件,因为 Android 文件结构对用户可见。
这里是苹果社区之前的讨论:https://discussions.apple.com/thread/3697948?start=0&tstart=0
The ONLY thing you can save to an iPhone, from Safari, is a pic. Nothing else, and no downloads.
iOS支持的视频文件以后有可能可以下载,但对于application/octet-stream
MIME类型的任意文件不太可能。
在我花了很多时间试图找到解决方案之后,我得出了这个解决方案:
将八位字节流替换为pdf。
<?php
$file = 'data/report/foobar.pdf';
header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: '.filesize($file));
readfile($file);
?>
我在 Node.js 中的标准 http
模块之上编写了一个 Web 服务器。它为我提供各种 HTML、JavaScript、CSS 和资产内容——自然而然地构成了我网页的大部分内容,这对我来说就像一个时钟。
当请求服务 URL 映射到具有未知扩展名的文件(没有进行 MIME 嗅探)时,它只是使用 header 的分块传输编码来提供内容Content-Type: application/octet-stream
,它也一直运行良好——我偶尔会在服务器上托管各种文件,并且能够在不受用户代理干扰的情况下下载这些文件,正如我对 application/octet-stream
的期望处理。
然而,今天,我尝试在 iOS 9.3.5 和 iPhone 4S 上的 Safari 移动浏览器 运行 下载,而那东西只是简单地拒绝从一个有效的 URL,提醒我:
Download failed. Safari cannot download this file.
我已经尝试添加 Content-Disposition: attachment
和 Content-Disposition: attachment; filename="foobar"
以取得更好的效果,但它仍然拒绝。
名为 random
的文件就是这种情况,其中填充了 1000 个随机字节。我的主机 header 是(Content-Disposition
是可选的,如上所述):
HTTP/1.1 200 OK
Host: example.com
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="foobar"
Date: Mon, 01 May 2017 13:48:37 GMT
Connection: keep-alive
Transfer-Encoding: chunked
根据记录,Android 6.x phone 也按预期运行(除了我的 Windows 10 x86_64 主机上的 Firefox 53),从 URL 顺利下载。
这里的 Safari 是怎么回事?
是的,您可以在 iOS 上使用 Safari 下载的唯一内容是图像。这是因为 iOS 不会向用户暴露文件结构(将文件下载到用户永远看不到的地方没有任何意义),它与防 Web 攻击无关。 Android 上的浏览器可以下载任意文件,因为 Android 文件结构对用户可见。
这里是苹果社区之前的讨论:https://discussions.apple.com/thread/3697948?start=0&tstart=0
The ONLY thing you can save to an iPhone, from Safari, is a pic. Nothing else, and no downloads.
iOS支持的视频文件以后有可能可以下载,但对于application/octet-stream
MIME类型的任意文件不太可能。
在我花了很多时间试图找到解决方案之后,我得出了这个解决方案:
将八位字节流替换为pdf。
<?php
$file = 'data/report/foobar.pdf';
header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: '.filesize($file));
readfile($file);
?>