前端(vue)入門到精通課程:進(jìn)入學(xué)習(xí)
閱讀本文,你將:
-
學(xué)會(huì)幾個(gè)超級(jí)超級(jí)實(shí)用的 響應(yīng)頭,解決你工作中遇到的問(wèn)題。
-
不僅解決問(wèn)題,還能讓你在 和后端、運(yùn)維撕逼時(shí) 占據(jù)上風(fēng)。
學(xué)習(xí) 響應(yīng)頭 很重要嗎?
真的很重要。
不信你看看下面的場(chǎng)景,眼熟不?
一、預(yù)覽、下載 讓人操碎了心?
1.1 場(chǎng)景
我不止一次聽(tīng)到同事、群友們討論這個(gè)問(wèn)題:
“后端提供了一個(gè)
txt
(或者url
,可以當(dāng)我用a
標(biāo)簽打開(kāi)時(shí),卻變成了預(yù)覽……怎么辦?救?。?!”
此時(shí),就會(huì)有人上去推薦 FileSaver.js
或者 “手寫讀流另存為”。
然后還有人附和…
我:???
這是需要寫代碼才能解決的問(wèn)題嗎?
如果你有了解過(guò) Content-Disposition
這個(gè) Response Header
,那你一定知道,只需要響應(yīng)頭上增加一行,問(wèn)題就能迎刃而解。
1.2 介紹
Content-Disposition
:這個(gè)響應(yīng)頭可以決定內(nèi)容是 預(yù)覽 還是 下載。
它支持三種格式的值:
-
Content-Disposition: inline
此時(shí),消息體會(huì)以頁(yè)面的一部分或者整個(gè)頁(yè)面的形式展示。(預(yù)覽) -
Content-Disposition: attachment
消息體應(yīng)該被下載,默認(rèn)文件名和url
格式有關(guān)。 -
Content-Disposition: attachment; filename="filename.jpg"
消息體應(yīng)該被下載,默認(rèn)文件名可指定。
注:如果需要預(yù)覽,需要配合適當(dāng)?shù)?
Content-Type
食用;
1.3 示例
為此,我特意寫了一個(gè) express
小示例。
大抵是在 express
應(yīng)用下寫了三個(gè)路由,如下:
const user = { name: "摸魚的春哥", blogUrl: "https://juejin.cn/user/1714893870865303" } const contentDispositionInline = async (req, res, next) => { res.setHeader('Content-Disposition', 'inline') res.send(user) } const contentDispositionFilename = async (req, res, next) => { res.setHeader('Content-Disposition', 'attachment; filename="chunge.json"') res.send(user) } const contentDispositionNoFilename = async (req, res, next) => { res.setHeader('Content-Disposition', 'attachment') res.send(user) }
然后我分別訪問(wèn)三個(gè)路由,效果差異:
二、項(xiàng)目升級(jí)了,需要客戶 清空緩存 ?
2.1 場(chǎng)景
實(shí)施:“客戶反饋Bug
還是沒(méi)修復(fù)?!?br />你:“哥,真修復(fù)了,要不你讓客戶清一下緩存?”
實(shí)施:“???客戶說(shuō)他不會(huì)清……”
……
永遠(yuǎn)不要期望你的客戶會(huì)進(jìn)行 “那些研發(fā)才懂” 的操作。也不要把你的問(wèn)題,歸因到 瀏覽器緩存 上。
瀏覽器緩存 是被發(fā)明出來(lái)優(yōu)化用戶體驗(yàn)的,并不是被發(fā)明出來(lái)阻礙用戶的。
因此,理解如何使用 Cache-Control
這個(gè)響應(yīng)頭,是前端的必知技能。
2.2 介紹
Cache-Control
:用來(lái)指定緩存機(jī)制。
緩存,作為前端八股文必考知識(shí),相信大家已經(jīng)耳熟能詳。 常見(jiàn)的 Cache-Control
屬性如下:
Response Header屬性 | 值 | 含義 |
---|---|---|
cache-control | no-store | 不緩存,這個(gè)會(huì)讓客戶端、服務(wù)器都不緩存,也就沒(méi)有所謂的強(qiáng)緩存、協(xié)商緩存了。 |
cache-control | public | 表明響應(yīng)可以被任何對(duì)象(包括:發(fā)送請(qǐng)求的客戶端,代理服務(wù)器,等等)緩存,即使是通常不可緩存的內(nèi)容。(例如:1.該響應(yīng)沒(méi)有max-age指令或Expires消息頭;2. 該響應(yīng)對(duì)應(yīng)的請(qǐng)求方法是 POST 。) |
cache-control | private | 表明響應(yīng)只能被單個(gè)用戶緩存,不能作為共享緩存(即代理服務(wù)器不能緩存它)。私有緩存可以緩存響應(yīng)內(nèi)容,比如:對(duì)應(yīng)用戶的本地瀏覽器。 |
cache-control | max-age=<1000> | 設(shè)置緩存存儲(chǔ)的最大周期,超過(guò)這個(gè)時(shí)間緩存被認(rèn)為過(guò)期(單位秒)。與Expires相反,時(shí)間是相對(duì)于請(qǐng)求的時(shí)間。 |
- 不緩存
不緩存是最容易理解,每一次請(qǐng)求都會(huì)從服務(wù)端重新獲取,不進(jìn)行任何緩存。
此策略只需要賦予Cache-Control: no-store
響應(yīng)頭即可。 - 強(qiáng)緩存
有些資源文件,幾乎不會(huì)發(fā)生變化(比如已經(jīng)hash化命名的文件
),則可以直接從本地緩存獲取,這就是所謂的 強(qiáng)緩存 ;
通過(guò)cache-control: public/private
或者cache-control: max-age=<1000>
都可以指定機(jī)制為強(qiáng)緩存。 - 協(xié)商緩存
這是一種更為復(fù)雜緩存機(jī)制,無(wú)法再通過(guò)響應(yīng)頭 簡(jiǎn)單粗暴地 指定實(shí)現(xiàn),而是需要前后端協(xié)作配合。
簡(jiǎn)單來(lái)說(shuō),每次請(qǐng)求資源前前端會(huì)寫代前一次的響應(yīng)hash
,問(wèn)詢服務(wù)端 資源是否發(fā)生過(guò)變化,從而達(dá)到準(zhǔn)確緩存的效果。
本文不贅述,如果有興趣,可以參考此文:juejin.cn/post/703078…
2.3 實(shí)際生產(chǎn)如何運(yùn)用?
- 凡是名稱帶有
hash
值的資源,一律可以強(qiáng)緩存。
(畢竟內(nèi)容一旦有變化,名稱的hash
也跟著變了) - 凡是通過(guò)
cdn
引入的第三方庫(kù),均建議攜帶版本信息,這樣也可以強(qiáng)緩存。
(比如/xx/xx/jquery.min.js
切換為jquery@3.6.0/dist/jquery.min.js
) - 凡是
html
、ico
這類命名固定的文件,建議一律 不緩存 或者 協(xié)商緩存。
三、我的 Cookie
不可能這么可愛(ài)!
3.1 場(chǎng)景
"春哥春哥,為啥我登錄成功了,請(qǐng)求還是
401
?"
"春哥春哥,為啥我存進(jìn)
cookie
的值取不到?"
"春哥春哥,這破
cookie
是不是壞了,瀏覽器里看明明有值,為啥我訪問(wèn)不了?"
我:“兄弟,你有了解過(guò)一個(gè)叫 set-cookie
的響應(yīng)頭嗎?”
是它!是它!就是它!關(guān)于 cookie
的各種異常,全靠它!
3.2 介紹
Cookie
曾經(jīng)是 Web
開(kāi)發(fā)無(wú)法繞開(kāi)的一道門檻,而現(xiàn)在它的存在感越來(lái)越弱,但海量的存量項(xiàng)目并不會(huì)因?yàn)榧夹g(shù)的趨勢(shì)而消失,它們依然很有價(jià)值,依然需要維護(hù)。
而 set-cookie
響應(yīng)頭正是 Cookie
體系中最為核心的 第一主角。
Set-Cookie
: 是一個(gè)響應(yīng)頭,服務(wù)端賦值,讓瀏覽器端產(chǎn)生 Cookie
,并限定 Cookie
的各種特性。
這些特性就包括:
- 過(guò)期時(shí)限;
Expires=<date>
- 存活周期;
Max-Age=<number>
在 cookie 失效之前需要經(jīng)過(guò)的秒數(shù)。0
或-1
直接失效;此屬性的優(yōu)先級(jí)高于Expires
。 - 域名;
Domain=<domain-value>
指定cookie
只能在什么域下生成;(允許通配,這個(gè)屬性主要出于安全性) - 路徑;
Path=<path-value>
比Domain
更為細(xì)致的控制策略,甚至指定了xx
路徑下才能發(fā)送Cookie
。 - 只在
Https
產(chǎn)生;Secure
如果set-cookie
頭中有Secure
屬性,那么瀏覽器只會(huì)在Https
環(huán)境產(chǎn)生和發(fā)送Cookie
。 - 禁用
js
操作API
;HttpOnly
如果set-cookie
頭中有HttpOnly
屬性,那么Cookie
屬性的生成、讀寫、發(fā)送就只能由瀏覽器通過(guò) "響應(yīng)頭" 控制了,不在允許前端通過(guò)js
操作Cookie
。 - 是否允許跨域攜帶;
SameSite=<samesite-value>
支持屬性包括Strict
、Lax
、None
,分別表示:Strict
: 完全不能跨域攜帶;Lax
: 只允許從外站導(dǎo)航到源站時(shí)攜帶Cookie
None
:跨域也行,不限制。
3.3 開(kāi)發(fā)常見(jiàn)問(wèn)題分析
-
為啥你登錄成功了,請(qǐng)求還是
401
?早期非常多的項(xiàng)目,使用
Cookie
作為用戶身份識(shí)別的手段,比如Spring MVC
項(xiàng)目就是通過(guò)給Cookie
一個(gè)JSeesionId
的值作為識(shí)別,判斷你是否出于當(dāng)前會(huì)話。而 "登錄了,卻還
401
" 這個(gè)現(xiàn)象,如果服務(wù)端沒(méi)有問(wèn)題的話,多半是 瀏覽器其實(shí)并未存儲(chǔ)Cookie。換個(gè)說(shuō)法,你每次發(fā)起請(qǐng)求,服務(wù)端都認(rèn)為你是一次 新的會(huì)話,和上一次 登錄的你 并非同一人。
如果你正處于
http
環(huán)境,那你可能需要暫時(shí)移除Secure
屬性。 -
存不進(jìn)、取不出?
先確認(rèn) 是否有域的限制、是否有路徑的限制、是否有HttpOnly
?
逐一排查下來(lái),問(wèn)題不難解決。
(學(xué)習(xí)視頻分享:web前端)