背景
我们有一个文件下载中心,提供一些软件、文档的下载。一直正常运行,但某天有同事反馈说他用手机下载某个软件的时候乱码了。
长这样
但我明明自己用手机试过,是能够正常下载的,是怎么回事呢?
问题排查
技术架构
这个文件服务其实很简单,直接使用 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多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。