天天看點

用頭解決!前端必知必會的幾個實用響應頭

📖閱讀本文,你将:

  1. 學會幾個超級超級實用的響應頭,解決你工作中遇到的問題。
  2. 不僅解決問題,還能讓你在和後端、運維撕逼時占據上風。

學習 響應頭 很重要嗎?

真的很重要。

不信你看看下面的場景,眼熟不?

一、預覽、下載下傳 讓人操碎了心?

1.1 場景

我不止一次聽到同僚、群友們讨論這個問題:

“後端提供了一個 ​

​txt​

​​(或者 ​

​pdf​

​​/'json' 等)檔案的下載下傳 ​

​url​

​​,可以當我用 ​

​a​

​ 标簽打開時,卻變成了預覽……怎麼辦?救!!!”

此時,就會有人上去推薦 ​

​FileSaver.js​

​ 或者 “手寫讀流另存為”。

然後還有人附和...

我:???

用頭解決!前端必知必會的幾個實用響應頭

這是需要寫代碼才能解決的問題嗎?

如果你有了解過 ​

​Content-Disposition​

​​ 這個 ​

​Response Header​

​,那你一定知道,隻需要響應頭上增加一行,問題就能迎刃而解。

1.2 介紹

​Content-Disposition​

​:這個響應頭可以決定内容是 預覽 還是 下載下傳。

它支援三種格式的值:

  1. ​Content-Disposition: inline​

    此時,消息體會以頁面的一部分或者整個頁面的形式展示。(預覽)

  2. ​Content-Disposition: attachment​

    ​​

    消息體應該被下載下傳,預設檔案名和 ​

    ​url​

    ​ 格式有關。
  3. ​Content-Disposition: attachment; filename="filename.jpg"​

    消息體應該被下載下傳,預設檔案名可指定。

注:如果需要預覽,需要配合适當的 ​

​Content-Type​

​ 食用;

1.3 示例

為此,我特意寫了一個 ​

​express​

​ 小示例。

大抵是在 ​

​express​

​ 應用下寫了三個路由,如下:

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)
}      

然後我分别通路三個路由,效果差異:

用頭解決!前端必知必會的幾個實用響應頭

二、項目更新了,需要客戶 清空緩存 ?

2.1 場景

實施:“客戶回報​

​Bug​

​ 還是沒修複。”

你:“哥,真修複了,要不你讓客戶清一下緩存?”

實施:“啊?客戶說他不會清……”

……

永遠不要期望你的客戶會進行 “那些研發才懂” 的操作。也不要把你的問題,歸因到 浏覽器緩存 上。

浏覽器緩存 是被發明出來優化使用者體驗的,并不是被發明出來阻礙使用者的。

是以,了解如何使用 ​

​Cache-Control​

​ 這個響應頭,是前端的必知技能。

2.2 介紹

​Cache-Control​

​:用來指定緩存機制。

緩存,作為前端八股文必考知識,相信大家已經耳熟能詳。

常見的 ​

​Cache-Control​

Response Header屬性 含義
cache-control no-store 不緩存,這個會讓用戶端、伺服器都不緩存,也就沒有所謂的強緩存、協商緩存了。
cache-control public 表明響應可以被任何對象(包括:發送請求的用戶端,代理伺服器,等等)緩存,即使是通常不可緩存的内容。(例如:1.該響應沒有max-age指令或Expires消息頭;2. 該響應對應的請求方法是 POST 。)
cache-control private 表明響應隻能被單個使用者緩存,不能作為共享緩存(即代理伺服器不能緩存它)。私有緩存可以緩存響應内容,比如:對應使用者的本地浏覽器。
cache-control max-age=<1000> 設定緩存存儲的最大周期,超過這個時間緩存被認為過期(機關秒)。與Expires相反,時間是相對于請求的時間。
  • 不緩存

    不緩存是最容易了解,每一次請求都會從服務端重新擷取,不進行任何緩存。

    此政策隻需要賦予​​

    ​Cache-Control: no-store​

    ​ 響應頭即可。
  • 強緩存

    有些資源檔案,幾乎不會發生變化(比如已經​​

    ​hash化命名的檔案​

    ​),則可以直接從本地緩存擷取,這就是所謂的強緩存;

    通過​​

    ​cache-control: public/private​

    ​​ 或者​

    ​cache-control: max-age=<1000>​

    ​ 都可以指定機制為強緩存。
  • 協商緩存

    這是一種更為複雜緩存機制,無法再通過響應頭簡單粗暴地指定實作,而是需要前後端協作配合。

    簡單來說,每次請求資源前前端會寫代前一次的響應​​

    ​hash​

    ​,問詢服務端資源是否發生過變化,進而達到準确緩存的效果。

    本文不贅述,如果有興趣,可以參考此文:​​​juejin.cn/post/703078…​​

2.3 實際生産如何運用?

  • 凡是名稱帶有​

    ​hash​

    ​​ 值的資源,一律可以強緩存。

    (畢竟内容一旦有變化,名稱的​​

    ​hash​

    ​ 也跟着變了)
  • 凡是通過​

    ​cdn​

    ​​ 引入的第三方庫,均建議攜帶版本資訊,這樣也可以強緩存。

    (比如​​

    ​/xx/xx/jquery.min.js​

    ​​ 切換為​

    [email protected]/dist/jquery.min.js​

    ​)
  • 凡是​

    ​html​

    ​​、​

    ​ico​

    ​ 這類命名固定的檔案,建議一律不緩存或者協商緩存。

三、我的 ​

​Cookie​

​ 不可能這麼可愛!

3.1 場景

"春哥春哥,為啥我登入成功了,請求還是 ​

​401​

​ ?"

"春哥春哥,為啥我存進 ​

​cookie​

​ 的值取不到?"

"春哥春哥,這破 ​

​cookie​

​ 是不是壞了,浏覽器裡看明明有值,為啥我通路不了?"

我:“兄弟,你有了解過一個叫 ​

​set-cookie​

​ 的響應頭嗎?”

用頭解決!前端必知必會的幾個實用響應頭

是它!是它!就是它!關于 ​

​cookie​

​ 的各種異常,全靠它!

3.2 介紹

​Cookie​

​​ 曾經是 ​

​Web​

​ 開發無法繞開的一道門檻,而現在它的存在感越來越弱,但海量的存量項目并不會因為技術的趨勢而消失,它們依然很有價值,依然需要維護。

而 ​

​set-cookie​

​​ 響應頭正是 ​

​Cookie​

​ 體系中最為核心的 第一主角。

​Set-Cookie​

​​: 是一個響應頭,服務端指派,讓浏覽器端産生 ​

​Cookie​

​​,并限定 ​

​Cookie​

​ 的各種特性。

這些特性就包括:

  • 過期時限;​

    ​Expires=<date>​

  • 存活周期;​

    ​Max-Age=<number>​

    ​​

    在 cookie 失效之前需要經過的秒數。​

    ​0​

    ​ 或 ​

    ​-1​

    ​ 直接失效;此屬性的優先級高于 ​

    ​Expires​

    ​。
  • 域名;​

    ​Domain=<domain-value>​

    ​​

    指定 ​

    ​cookie​

    ​ 隻能在什麼域下生成;(允許通配,這個屬性主要出于安全性)
  • 路徑;​

    ​Path=<path-value>​

    ​​

    比 ​

    ​Domain​

    ​ 更為細緻的控制政策,甚至指定了 ​

    ​xx​

    ​ 路徑下才能發送 ​

    ​Cookie​

    ​。
  • 隻在​

    ​Https​

    ​​ 産生;​

    ​Secure​

    ​​

    如果 ​

    ​set-cookie​

    ​ 頭中有 ​

    ​Secure​

    ​ 屬性,那麼浏覽器隻會在 ​

    ​Https​

    ​ 環境産生和發送 ​

    ​Cookie​

    ​。
  • 禁用​

    ​js​

    ​​ 操作​

    ​API​

    ​​;​

    ​HttpOnly​

    ​​

    如果 ​

    ​set-cookie​

    ​ 頭中有 ​

    ​HttpOnly​

    ​ 屬性,那麼 ​

    ​Cookie​

    ​ 屬性的生成、讀寫、發送就隻能由浏覽器通過 "響應頭" 控制了,不在允許前端通過 ​

    ​js​

    ​ 操作 ​

    ​Cookie​

    ​。
  • 是否允許跨域攜帶;​

    ​SameSite=<samesite-value>​

  • 支援屬性包括 ​

    ​Strict​

    ​、​

    ​Lax​

    ​、​

    ​None​

    ​,分别表示:
    • ​Strict​

      ​: 完全不能跨域攜帶;
    • ​Lax​

      ​: 隻允許從外站導航到源站時攜帶 ​

      ​Cookie​

    • ​None​

      ​:跨域也行,不限制。

3.3 開發常見問題分析

  • 為啥你登入成功了,請求還是​

    ​401​

    ​?

    早期非常多的項目,使用​

    ​Cookie​

    ​ 作為使用者身份識别的手段,比如 ​

    ​Spring MVC​

    ​ 項目就是通過給 ​

    ​Cookie​

    ​ 一個 ​

    ​JSeesionId​

    ​ 的值作為識别,判斷你是否出于目前會話。

    而 "登入了,卻還​

    ​401​

    ​" 這個現象,如果服務端沒有問題的話,多半是 浏覽器其實并未存儲Cookie。

    換個說法,你每次發起請求,服務端都認為你是一次新的會話,和上一次 登入的你 并非同一人。

    如果你正處于​

    ​http​

    ​ 環境,那你可能需要暫時移除 ​

    ​Secure​

    ​ 屬性。
  • 存不進、取不出?

    先确認 是否有域的限制、是否有路徑的限制、是否有 ​

    ​HttpOnly​

    ​​?

    逐一排查下來,問題不難解決。

四、結束語

繼續閱讀