問(wèn)題表現(xiàn)
解決過(guò)程
如果你的pdf下載鏈接是存在oss上的,那么請(qǐng)復(fù)制你的鏈接葬燎,將你的鏈接粘貼到瀏覽器中窜醉,然后打開(kāi)控制臺(tái),查看以下幾個(gè)參數(shù)
先了解這些參數(shù)的含義
1.content-disposition
這個(gè)參數(shù)一般情況下傳兩個(gè)值瞧预,分別是attachment和filename屎债,其中attachment還可傳inline,也就是它可能會(huì)出現(xiàn)以下傳值
content-disposition: attachment;filename=xxx.pdf;
content-dispostion: inline;filename=xxx.pdf
其中當(dāng)值是 attachment 時(shí)垢油,瀏覽器會(huì)觸發(fā)自動(dòng)下載盆驹,這一句是關(guān)鍵,你應(yīng)該首先檢查是否包含attachment滩愁,反之如果不填或者為Inline時(shí)躯喇,則會(huì)觸發(fā)預(yù)覽,而不是下載硝枉。
其次是filename字段廉丽,當(dāng)瀏覽器觸發(fā)下載時(shí),瀏覽器會(huì)默認(rèn)取filename字段作為文件標(biāo)題檀咙,在微信瀏覽器中雅倒,同樣會(huì)默認(rèn)取filename字段作為標(biāo)題。
當(dāng)微信瀏覽器中filename為null時(shí)弧可,應(yīng)首先想辦法檢查filename是否為空蔑匣。
當(dāng)在同源策略中,比如你在https://www.123.com域名下棕诵,下載一個(gè)https://www.123.com/file.pdf的文件裁良,由于他們處于同一個(gè)域中,瀏覽器可能會(huì)優(yōu)先取a標(biāo)簽中的download字段校套。當(dāng)不使用a標(biāo)簽觸發(fā)下載時(shí)价脾,瀏覽器將取content-dispostion中多個(gè)filename字段。
1.1更多關(guān)于filename的細(xì)節(jié)
除了可以傳filename之外笛匙,我們還可以傳filename*侨把,就是結(jié)尾多了一個(gè)星號(hào)。更多的解釋請(qǐng)查閱https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition妹孙。
簡(jiǎn)而言之秋柄,filename允許你傳入中文,但是在舊版本瀏覽器中蠢正,filename中文可能會(huì)出現(xiàn)文件名亂碼問(wèn)題骇笔。
為了解決這個(gè)問(wèn)題,你應(yīng)當(dāng)盡量保持filename經(jīng)過(guò)了JavaScript的encodeURI或encodeURIComponent編碼處理,這兩種方法的區(qū)別是encodeURI不會(huì)對(duì)特殊符號(hào)轉(zhuǎn)譯笨触,而后綴會(huì)對(duì)特殊符號(hào)進(jìn)行轉(zhuǎn)譯懦傍,推薦使用后者。
====================
encodeURIComponent將文本轉(zhuǎn)為unicode編碼后芦劣,依照RFC3986協(xié)議進(jìn)行編:https://datatracker.ietf.org/doc/html/rfc3986
encodeURL將文本轉(zhuǎn)為unicode編碼后粗俱,依照協(xié)議 RFC2396協(xié)議進(jìn)行編:https://www.ietf.org/rfc/rfc2396.txt (encodeURL不會(huì)對(duì)特殊符號(hào)進(jìn)行轉(zhuǎn)譯。)
======================
在早期瀏覽器版本中虚吟,由于filename一直是一個(gè)受爭(zhēng)議的規(guī)范源梭,各大瀏覽器實(shí)現(xiàn)有差異,參考rfc5987規(guī)范https://datatracker.ietf.org/doc/html/rfc5987#section-3.2.2稍味。你可以在filename基礎(chǔ)上,再加上一個(gè)filename*荠卷,filename*告訴瀏覽器后面接的一定是一段編碼模庐,主流瀏覽器都將遵守以下規(guī)范:
當(dāng)filename和fiename*同時(shí)存在時(shí),優(yōu)先使用filename*油宜,當(dāng)filename和filename*都不存在時(shí)掂碱,瀏覽器默認(rèn)取URL中的后綴作為文件名。于是會(huì)有以下代碼
content-disposition: attachment;filename=encodeURIComponent(文件名.pdf);filename* =UTF-8''encodeURIComponent(文件名稱(chēng).pdf);
我們重點(diǎn)關(guān)注filename* =UTF-8''encodeURIComponent(文件名稱(chēng).pdf)即可慎冤。微信瀏覽器以及各大主流瀏覽器疼燥,都會(huì)默認(rèn)取這個(gè)字段
1.2差異
filename字段理論上可直接傳中文,但上傳騰訊云時(shí)蚁堤, content-disposition字段不支持直接傳中文醉者,需進(jìn)行編碼。
在safari中披诗,不會(huì)對(duì)filename進(jìn)行解碼撬即,如果你只填寫(xiě)了filename,而filename剛好是一段編碼呈队,PC瀏覽器可能會(huì)正常顯示下載文件名剥槐,但safari不會(huì)對(duì)filename進(jìn)行解碼,只會(huì)對(duì)filename*進(jìn)行解碼宪摧,可能會(huì)直接顯示一段編碼原文粒竖。加上filename*可兼容safari。
2.content-type
如果你的content-type為application/pdf几于,在PC中會(huì)自動(dòng)觸發(fā)下載蕊苗,但在safari中,可能會(huì)出現(xiàn)預(yù)覽而不是下載孩革,此時(shí)你應(yīng)該將此字段設(shè)置為:
content-type:application/octet-stream
以上是告訴瀏覽器岁歉,獲取的是一個(gè)文件流,safari會(huì)對(duì)此文件進(jìn)行下載,而不是預(yù)覽锅移。
3.如何配置上述的參數(shù)
如果你使用的oss是騰訊云熔掺,在上傳文件時(shí),會(huì)調(diào)用sdk的uploadFile方法非剃,此方法支持配置上傳文件的contentType和contentDisposition置逻,上傳完畢后,生成的訪問(wèn)鏈接就自動(dòng)攜帶這些屬性备绽。 如果你想對(duì)已有的文件進(jìn)行測(cè)試券坞,你可以到oss列表中,找到你要測(cè)試的文件肺素,找到"自定義header"設(shè)置恨锚,可以為其手動(dòng)添加參數(shù)。 但這些都基于騰訊云oss倍靡。 如果你使用的是阿里云oss猴伶,解決思路也是一樣的,可按照我說(shuō)的解決思路尋找對(duì)應(yīng)方案塌西,其目的都是為了將你的oss文件上傳時(shí)加上這些參數(shù)他挎。
總結(jié):
上傳oss文件時(shí),需配置content-disposition參數(shù)和content-type參數(shù)捡需,方法上文已說(shuō)明办桨,不再贅述。
最后的小坑
不推薦使用騰訊云getObjectUrl方法獲取下載鏈接站辉,你應(yīng)該始終是訪問(wèn)原始鏈接進(jìn)行下載呢撞。通過(guò)getObjectUrl返回的鏈接,騰訊云可能會(huì)對(duì)你拼接的response-content-disposition參數(shù)進(jìn)行轉(zhuǎn)碼庵寞,到了微信瀏覽器中狸相,反而會(huì)出現(xiàn)亂碼,此問(wèn)題需注意捐川。