背景
我们有一个文件下载中心,提供一些软件、文档的下载。一直正常运行,但某天有同事反馈说他用手机下载某个软件的时候乱码了。
长这样
但我明明自己用手机试过,是能够正常下载的,是怎么回事呢?
问题排查
技术架构
这个文件服务其实很简单,直接使用 Nginx 作为文件服务器,利用 alias 指令映射请求的 URI 到文件系统的路径。类似这样:
location ^~ /download/software {
alias "/";
sendfile on;
limit_rate 1024k;
absolute_redirect off;
}
ps: alias 和 root 都是用来做服务器路径映射的,只不过规则有差异。
思路
其实这个问题还是比较好查的,下载是浏览器行为,而且不同的浏览器表现有差异。
那么优先查浏览器就好了,那位同事使用的是 Firefox,而我小米手机自带的浏览器则是 Chrome 内核。
看起来就是 Firefox 不支持某些下载场景。
想到这里,我就有点好奇,浏览器的下载行为究竟是由谁来控制,它怎么知道要下载?
浏览器下载行为
下载都是一个个 HTTP请求,那想必和请求的响应头有关。
Content-Disposition
这个响应头我是很熟悉的,写下载文件的代码的时候,经常要给它指定文件名,例如
Content-Disposition: attachment; filename="example.pdf"
如果文件名是中文,通常还要做url编码。
其实这个响应头的主要作用是控制浏览器预览还是直接下载文件。 常见的值有两个:
-
inline:指示浏览器预览内容(如果浏览器支持),比如一些 pdf 文件 -
attachment:指示浏览器下载内容并提示用户保存文件,也即是我们常写的代码
Content-Type
这个响应头指定了相应内容的媒体类型(MIME 类型)。浏览器根据这个头信息来决定如何解析和显示响应内容。
我罗列了一些常见的Content-Type值:
-
文本文件:text/html、text/plain、text/css、application/javascript -
图像文件:image/jpeg、image/png -
应用程序文件:application/json、application/octet-stream
回到问题
那么我的下载请求的响应头是什么? 
居然是text/plain,居然是个文本!!!
(不得不说Chrome还是NB的,这都能下载)
接下来就是chapt时间:
Nginx 会使用mime.types文件来确定响应内容的Content-Type,这个文件里包含了常见的文件扩展名和MIME类型的映射规则。
但我的文件里并没有 apk 文件的规则。
[root@localhost conf]# cat mime.types | grep apk
[root@localhost conf]#
而如果文件扩展名不在mime.types文件中,Nginx 将使用default_type指令来设置默认类型,于是我查了下我的配置:
default_type text/plain;
这下破案了。
如何解决
通过上面的文章,至少能知道两种方案:
-
修改 mime.types文件 -
修改 default_type
其实还有第三种方法,Nginx 提供了type指令来设置Content-Type。
location ^~ /download/software {
types {
default_type application/octet-stream;
}
alias "/";
sendfile on;
limit_rate 1024k;
absolute_redirect off;
}
搞定收工。
本文由 mdnice 多平台发布
3888

被折叠的 条评论
为什么被折叠?



