Open HelloChunWei opened 3 years ago
前幾個月忙於改寫公司 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 上的瀏覽器也符合我的預期的操作了。
從 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 也會保存的原因。
Invalid or no expiration, persistent cookie
那麼 IOS 呢?
從原始碼可以看到,IOS chrome對於 cookie 的處理是遵循 NSHTTPCookieStorage 做處理,那裡面有提到:如果沒有設定 Max-age 的話,關閉掉瀏覽器則會自動清除。
這也是為什麼 IOS 的 chrome 處理會和 pc 上的不一樣。
這一次的經驗是我第一次看 RFC 文件(2019/07),在那之前其實沒有預想到自己有一天會看RFC文件,但熟悉之後可以從RFC文件中了解到滿多資訊的,再加上RFC的文件才是準確的,例如之前的 async/await 其實是 ECMA2017 (ES8) 的規範,並不是 ECMA2016 (ES7),所以各位有機會的話,不仿去看看 RFC 文件吧。
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:
裡面有寫到
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 文件吧。