问题表现
image.jpg解决过程
如果你的pdf下载链接是存在oss上的,那么请复制你的链接,将你的链接粘贴到浏览器中,然后打开控制台,查看以下几个参数
image.png
先了解这些参数的含义
1.content-disposition
这个参数一般情况下传两个值,分别是attachment和filename,其中attachment还可传inline,也就是它可能会出现以下传值
content-disposition: attachment;filename=xxx.pdf;
content-dispostion: inline;filename=xxx.pdf
其中当值是 attachment 时,浏览器会触发自动下载,这一句是关键,你应该首先检查是否包含attachment,反之如果不填或者为Inline时,则会触发预览,而不是下载。
其次是filename字段,当浏览器触发下载时,浏览器会默认取filename字段作为文件标题,在微信浏览器中,同样会默认取filename字段作为标题。
当微信浏览器中filename为null时,应首先想办法检查filename是否为空。
当在同源策略中,比如你在https://www.123.com域名下,下载一个https://www.123.com/file.pdf的文件,由于他们处于同一个域中,浏览器可能会优先取a标签中的download字段。当不使用a标签触发下载时,浏览器将取content-dispostion中多个filename字段。
1.1更多关于filename的细节
除了可以传filename之外,我们还可以传filename*,就是结尾多了一个星号。更多的解释请查阅https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition。
简而言之,filename允许你传入中文,但是在旧版本浏览器中,filename中文可能会出现文件名乱码问题。
为了解决这个问题,你应当尽量保持filename经过了JavaScript的encodeURI或encodeURIComponent编码处理,这两种方法的区别是encodeURI不会对特殊符号转译,而后缀会对特殊符号进行转译,推荐使用后者。
====================
encodeURIComponent将文本转为unicode编码后,依照RFC3986协议进行编:https://datatracker.ietf.org/doc/html/rfc3986
encodeURL将文本转为unicode编码后,依照协议 RFC2396协议进行编:https://www.ietf.org/rfc/rfc2396.txt (encodeURL不会对特殊符号进行转译。)
======================
在早期浏览器版本中,由于filename一直是一个受争议的规范,各大浏览器实现有差异,参考rfc5987规范https://datatracker.ietf.org/doc/html/rfc5987#section-3.2.2。你可以在filename基础上,再加上一个filename*,filename*告诉浏览器后面接的一定是一段编码,主流浏览器都将遵守以下规范:
当filename和fiename*同时存在时,优先使用filename*,当filename和filename*都不存在时,浏览器默认取URL中的后缀作为文件名。于是会有以下代码
content-disposition: attachment;filename=encodeURIComponent(文件名.pdf);filename* =UTF-8''encodeURIComponent(文件名称.pdf);
我们重点关注filename* =UTF-8''encodeURIComponent(文件名称.pdf)即可。微信浏览器以及各大主流浏览器,都会默认取这个字段
1.2差异
filename字段理论上可直接传中文,但上传腾讯云时, content-disposition字段不支持直接传中文,需进行编码。
在safari中,不会对filename进行解码,如果你只填写了filename,而filename刚好是一段编码,PC浏览器可能会正常显示下载文件名,但safari不会对filename进行解码,只会对filename*进行解码,可能会直接显示一段编码原文。加上filename*可兼容safari。
2.content-type
如果你的content-type为application/pdf,在PC中会自动触发下载,但在safari中,可能会出现预览而不是下载,此时你应该将此字段设置为:
content-type:application/octet-stream
以上是告诉浏览器,获取的是一个文件流,safari会对此文件进行下载,而不是预览。
3.如何配置上述的参数
如果你使用的oss是腾讯云,在上传文件时,会调用sdk的uploadFile方法,此方法支持配置上传文件的contentType和contentDisposition,上传完毕后,生成的访问链接就自动携带这些属性。 如果你想对已有的文件进行测试,你可以到oss列表中,找到你要测试的文件,找到"自定义header"设置,可以为其手动添加参数。 但这些都基于腾讯云oss。 如果你使用的是阿里云oss,解决思路也是一样的,可按照我说的解决思路寻找对应方案,其目的都是为了将你的oss文件上传时加上这些参数。
总结:
上传oss文件时,需配置content-disposition参数和content-type参数,方法上文已说明,不再赘述。
最后的小坑
不推荐使用腾讯云getObjectUrl方法获取下载链接,你应该始终是访问原始链接进行下载。通过getObjectUrl返回的链接,腾讯云可能会对你拼接的response-content-disposition参数进行转码,到了微信浏览器中,反而会出现乱码,此问题需注意。
网友评论