項目中使用了持久化登陸,即首次登陸后將 Cookie 保存到本地,下次進入應用時可以免登陸操作(此項由 React Naitve 幫助我們完成,只要服務器設置了 Set-Cookie 響應頭即可,Cookie 失效的時間由服務器確定)。
應用的邏輯是這樣的:首次使用應用時需要登陸,登陸成功后后端在本地種植 Cookie,下次開啟應用時無需再進行登陸,每次請求接口時都會帶上 Cookie,后端校驗如果 Cookie 失效會將請求重定向至 AuthFailed,一旦請求重定向至 AuthFailed,就需要跳轉到登錄界面重新登陸。
一直以來,這項功能都穩定和諧的運行著,直到有一天我突發奇想:如果在登陸后立馬退出應用,會是一種怎樣的體驗呢?從此走向了一條不歸路……
我發現在登陸后立馬退出應用,下次再進入應用時仍然會跳轉到登陸頁面(我們在應用功能啟動時會有一個驗證操作,校驗 Cookie 是否有效,如果失效就會跳轉到登錄頁面),這令人百思不得其解。
其實一開始我并沒有意識到這是 Android 下 Cookie 保存機制的問題,因為在那之前我增加了新的功能,自然而然想到是新功能引起的 bug,但我一直找不到 bug
是由什么引起的,后來當我一個 Commit 一個 Commit 進行回退驗證,直至回退到上一個穩定版本,還是出現了這個問題。
我開始懷疑是后端接口的問題,于是開始抓包分析,發現有時候請求頭中并沒有帶上 Cookie,而 IOS 下又沒有此問題,我就想是不是安卓下無法正常的保存 Cookie,按照這個思路,我做了以下嘗試:
- 使用 react-native-cookies 在登陸成功后手動設置 Cookie
- 設置
fetch
請求頭的credentials
項為include
或者same-origin
此外,還進行大量的搜索,查看 Issue 等,結果都是失敗。
后面偶然間發現了一篇文章,說道這可能是 Android 下 Cookie 保存機制的問題:
Synchronize the browser cookie store between RAM and permanent storage.
To get the best performance, browser cookies are saved in RAM.
A separate thread saves the cookies between, driven by a timer.
…
The sync interval is 5 minutes, so you will want to force syncs manually anyway.
文章鏈接在此。
也就是說,當我登陸成功后立馬退出應用,Android 端可能還來不及保存 Cookie,造成下一次登錄時持久化失效。按照文章中的解決方案修改了 MainActivity.java
文件,再次執行前面的變態操作,也就可以了。以下是新增的配置代碼(增加了原文中沒有導入的兩個包):
// Handle Cookies
import android.webkit.CookieSyncManager;
import android.os.Build;
import android.webkit.CookieManager;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initCookie();
}
@Override
protected void onStop() {
saveCookie();
super.onStop();
}
private void initCookie() {
if (Build.VERSION.SDK_INT < 21) CookieSyncManager.createInstance(this);
}
private void saveCookie() {
if (Build.VERSION.SDK_INT >= 21) CookieManager.getInstance().flush();
else CookieSyncManager.getInstance().sync();
}
}
真是無力吐槽,心力交瘁……
完。