在某个风和日丽的下午,我们项目上预发布了,一切看似风平浪静,直至测试童鞋在群里说了一句“为什么这个csv文件下载下来变成了txt?”。csv文件是放在前端的静态资源里打包的,且作为bug路由器的前端童鞋,自然得肩负起解决这个问题的责任。
背景提示:文件放置在腾讯云cdn中,线上的cdn配置和预发布的cdn配置一样,线上的csv下载正常。通过nginx配置资源访问。
这个文件在代码里是这么写的:
<a download="模板文件.csv" href="/assets/example/模板文件.csv">模板文件</a>
莫非是a标签的download属性的兼容性问题? 我使用的是Chrome浏览器下载文件,在查阅了大量的资料后,排除了这个想法。这时,我搜索看到了一种说法:和content-type有关,这个以往看HTTP时经常能看到的却没太引起我重视的头部。MDN的解释为:
Content-Type 实体头部用于指示资源的MIME类型 media type 。
秉承着对预上线环境的敬畏之心,我改了本地的nginx配置,在nginx.conf里简单配置了如下内容:
location /foo {
# 中间省略
if ($uri ~ 'csv$') {
// 当匹配到csv后缀时进到这里
add_header Content-Disposition ‘attachment; filename=“$fname”’;
add_header Content-Type text/csv;
}
}
这里我加了两个header,Content-Disposition和Content-Type。前者确保下载下来的是文件,后者确保格式是正确的。当然在我本机上是正常的,本机没能完全复现预生产环境的配置(毕竟预生产还上了cdn等一系列东西)。我进行了大量的尝试,比如讲text/csv写成text/plain,下载的之后果然是txt文件。
第二天,我拿着这份配置找到了运维童鞋,希望在nginx.conf里加入这个配置。然而事实却不如我预想中的一样,加上了配置之后下载的csv还是txt,且响应头里的content-type还是text/plain。
在改配置无果后,我重新看了MDN关于Content-Type的定义,确定了这个MIME类型的可能就是问题产生的原因。于是根据MINE TYPES文档的提示, 找运维童鞋对比了线上和预发布环境的nginx的mime_types的配置,果然在预发布少了一行:
text/csv csv
添加完毕,重启nginx后居然还是txt文件,且响应头content-type还是text/plain。不过至少排除了一个可疑点。接着再去排查腾讯云的配置,因为以往发生过腾讯云缓存的问题,接着我们去刷新了腾讯云的文件,五分钟后刷新完毕,无果。
但在搜索腾讯云、content-type之后又看到一篇文章腾讯云头部缓存配置
啥?除了会缓存文件,居然还会缓存头部?666。果然,配置里居然开启了“缓存源站所有头部”,于是将其关闭。焦急地等待了五分钟后,终于成功了!下载的csv终于不是txt了。
长舒一口气后,我回想起昨天的那个风和日丽的下午的那句“为什么这个csv文件下载下来变成了txt?”,窃笑了一声,然后痛快地喝了几口肥宅快乐水。