HelloChunWei / blog

個人部落格,紀錄自己的知識
MIT License
7 stars 0 forks source link

cookie? 說難不難,說簡單不簡單 #5

Open HelloChunWei opened 3 years ago

HelloChunWei commented 3 years ago

cookie? 說難不難,說簡單不簡單

前言

前幾個月忙於改寫公司 webview APP(改用 flutter 開發),所以就疏於整理了。這一次遇到的 cookie 問題大約是一年前遇到的,剛好趁著這個機會好好紀錄一下。 cookie 原本我以為也就那樣,遇到不熟的屬性大概查一下就好了,但這一次我錯了

先說結論

pc 上的 chrome 以及 safari 對於沒有設定期限的 cookies 是永久保存,IOS 上的 chrome 及 safari 則是 session 斷掉後就會清空cookies。Android 上的瀏覽器則跟 pc 相同。

萬事起個頭

大概去年的7月吧(2019/07),我發現專案上 cookie 的行為與預期的不同,pc上的 chrome 操作是正常的,但是 IOS 不管什麼瀏覽器,只要 session 一斷,cookie 就會自動清空,我們專案是在後端(NodeJS)操作 cookie,所以我先去後端的專案看一下 cookies 的設定,恩~~~ 看起來也沒什麼問題。

但不管我怎麼試,IOS 的瀏覽器都會清空 cookie。

決定把思路在後退一點

由於已經卡了很久,所以決定先從 RFC 來確認 cookie 的規範。

後來找到這一份 RFC 裡面有提到 「一個 session 結束掉」,是每個瀏覽器自己定義的,看到這一份文件後,心想會不會是 Max-age 設定的問題? 所以回頭去認真看專案中對於 cookie 中期限(Max-age)的設定,才發現同事把 Max-age 的單位寫錯了,導致 Max-age 設定失效,所以會被當作沒設定 Max-age 屬性。

原來繞了一大圈,問題是出在 Max-age 單位錯誤的問題,原本看到 Max-age 有設定,就不疑有他覺得同事寫的應該是對的,結果沒想到竟然是錯的。

最後把 Max-age 設定好之後,IOS 上的瀏覽器也符合我的預期的操作了。

為什麼 pc 的chrome 操作和 IOS 上的不一樣?

從 chromium 的原始碼來看,有一個CanonExpiration 的function:

// static
Time CanonicalCookie::CanonExpiration(const ParsedCookie& pc,
                                      const Time& current,
                                      const Time& server_time) {
  // First, try the Max-Age attribute.
  uint64_t max_age = 0;
  if (pc.HasMaxAge() &&
#ifdef COMPILER_MSVC
      sscanf_s(
#else
      sscanf(
#endif
             pc.MaxAge().c_str(), " %" PRIu64, &max_age) == 1) {
    return current + TimeDelta::FromSeconds(max_age);
  }
  // Try the Expires attribute.
  if (pc.HasExpires() && !pc.Expires().empty()) {
    // Adjust for clock skew between server and host.
    base::Time parsed_expiry =
        cookie_util::ParseCookieExpirationTime(pc.Expires());
    if (!parsed_expiry.is_null())
      return parsed_expiry + (current - server_time);
  }
  // Invalid or no expiration, persistent cookie.
  return Time();
}

裡面有寫到 Invalid or no expiration, persistent cookie 如果 Max-age 沒設置或者設置錯誤,chrome 會把它永久保存,所以這就是為什麼我的專案 Max-age 設置錯誤,但是 pc 上的 chrome 也會保存的原因。

那麼 IOS 呢?

原始碼可以看到,IOS chrome對於 cookie 的處理是遵循 NSHTTPCookieStorage 做處理,那裡面有提到:如果沒有設定 Max-age 的話,關閉掉瀏覽器則會自動清除。

這也是為什麼 IOS 的 chrome 處理會和 pc 上的不一樣。

結論

這一次的經驗是我第一次看 RFC 文件(2019/07),在那之前其實沒有預想到自己有一天會看RFC文件,但熟悉之後可以從RFC文件中了解到滿多資訊的,再加上RFC的文件才是準確的,例如之前的 async/await 其實是 ECMA2017 (ES8) 的規範,並不是 ECMA2016 (ES7),所以各位有機會的話,不仿去看看 RFC 文件吧。