中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

異步處理ServletRequest引發的血案

發布時間:2020-08-11 08:55:13 來源:網絡 閱讀:742 作者:nxlhero 欄目:軟件技術

我們的APP生產上出了一次比較嚴重的事故,許多用戶投訴登錄后能看到別人的信息,收到投訴后我們就開始查找問題,一般這樣的問題都是線程安全引起的,所以查找原因的思路也是按線程安全的思路去查。

業務場景是這樣的,用戶登錄后,點擊一個頁面查看信息,這個信息顯示了別人的信息。

登錄交易大致流程如下:

//一系列驗證
session.setAttribute("id",id); //證件號放入session
//其他操作

查看信息交易的流程如下:

session = request.getSession();
if(session != null && session.getAttribute("LoginStatus") == True) {
    String id = session.getAttribute("id");
    Information info = queryInfo(id);
    return info;
} else {
    return "not login";
}

通過加日志等方法,我們確認了是查看信息的時候,從session里拿出來的證件號是其他人的,但是到底是在什么時候變化的,沒找到,因為我們一直順著線程安全的思路,找全局變量這樣的地方。

另外還發現有個地方可疑,就是有一個異步的線程,會驗證用戶證件號,并且重新在session里放一次。

public void updateId(HttpServletRequest request) {
    HttpSession session = request.getSession();
    String id = validate();
    session.setAttribute("id",id);
}

這個函數是在登錄主交易調起的線程池處理的,看上去其實沒有多大毛病,而且也是老的代碼,很久了。而且我發現了一個規律,被別人看到信息的用戶,登錄交易都觸發了使用新設備登錄,因為我們加了一個邏輯,對換設備登錄做了驗證,這樣的話需要驗證短信,登錄分兩步了,第一步比較快的返回了,但是異步的更新信息流程還在。

異步處理ServletRequest引發的血案

于是我懷疑是不是因為Servlet的交易已經返回了,異步的線程雖然拿到了HttpServletRequest,但是這個request已經無效了或者被復用了。

我寫了下面的代碼進行驗證,不停的用curl調用。Http請求很快就返回了,但是我會把HttpServletRequest傳給一個線程池,等5s后才會去處理這個Request,結果果然是有問題的

異步處理ServletRequest引發的血案

結果果然有問題,大部分情況new_session都是null,但也出現了不是null的情況,這時候發現session不是自己的。
異步處理ServletRequest引發的血案
HttpServletRequest是有生命周期的,當一個http請求過來后,應用服務器解析報文,把各種參數放到一個HttpServletRequest對象中,然后傳遞給Servlet的service函數,service函數根據里面的方法調用對應的doGet/doPost等方法,而一旦service函數調用結束,HttpServletRequest的生命周期就結束了,再這之后你繼續使用這個對象,產生的結果是不確定的。
異步處理ServletRequest引發的血案
網上遇到這類問題的人不多,我專門找了servlet specification,其中有一章講HttpServletRequest生命周期的。
異步處理ServletRequest引發的血案
從中可以得到如下信息:

(1)三種情況下request有效:service函數內,doFilter函數內,startAsync起的異步線程

(2)在三種情況之外,使用request會產生不確定的結果(indeterminate results)

(3)大部分容器在實現servlet的時候,為了提高性能,會復用request對象,但這不是規范里必須的

其中提到的startAsync是servlet 3.0開始有的,它是為了讓一個工作線程可以在做IO或類似阻塞線程的操作的時候能干其它的事情,但是它要求異步線程都結束了,才會將請求返回給客戶端,本質上還是同步的,只是并行了。所以要想異步的處理Request,必須使用servlet自己的異步機制,但是這樣并不能滿足我們的需求,因為我們就是為了不讓主線程等待。

用法示例:
異步處理ServletRequest引發的血案

如果使用了這個,那么客戶端需要等待5s才能拿到結果。

我又看了tomcat的源碼,發現它確實對Request做了復用:
異步處理ServletRequest引發的血案

雖然問題的原因很簡單,但是產生的后果十分嚴重。需要異步處理數據的時候一定要特別小心,此處如果傳Session就沒問題了,但是還是要盡量避免。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

穆棱市| 连云港市| 沙田区| 寿宁县| 凭祥市| 滦南县| 临朐县| 得荣县| 称多县| 白银市| 陇西县| 乐山市| 遂昌县| 前郭尔| 崇义县| 轮台县| 青岛市| 香河县| 濮阳县| 壤塘县| 保定市| 延吉市| 中山市| 雷山县| 柞水县| 海安县| 河南省| 肇庆市| 绥芬河市| 洛阳市| 麻城市| 靖宇县| 公主岭市| 青铜峡市| 闽清县| 澳门| 海阳市| 广昌县| 新源县| 台山市| 漠河县|