一次呼叫支付寶PC場景下單筆支付之後同步回撥遇到的session失效問題記錄
問題描述:
呼叫支付寶介面:alipay.trade.page.pay,該介面請求引數中有兩個返回地址需要設定,return_url是同步返回地址,用於支付成功後頁面的跳轉,notify_url是非同步通知地址,用於支付寶伺服器主動通知商戶伺服器裡指定的頁面。問題出在同步返回的時候,因為業務需要返回的地址需要使用者的登陸資訊,專案中的用的session會話管理,但是呼叫支付寶支付介面支付成功後返回該同步頁面時,卻被攔截器攔截,跳到登陸頁面,需要輸入使用者的登陸資訊,這種情況是不能忍的。。。⊙o⊙
問題分析:
1.考慮到這種情況,首先想到的就是session失效,可是session為什麼會失效呢?
首先,session是伺服器端為了儲存狀態而建立的一個特殊的物件。瀏覽器訪問伺服器時,伺服器建立一個特殊物件session(該物件有一個唯一的id,稱為sessionId,伺服器會將sessionId以cookie形式發給瀏覽器,當瀏覽器再次訪問伺服器時,會將sessionId傳送過來,伺服器端可以利用這個sessionId找到相應的session物件)。
到此處判斷是支付寶同步返回return_url的時候沒有將sessionId發給瀏覽器,那我就把sessionId發給伺服器,採用的解決辦法是url重寫,將sessionId拼接到return_url後面,格式為?SESSION=sessionId,嘗試結果失敗 >"<||||
為什麼會失敗呢,代表用這種方式伺服器依然無法獲得sessionId,伺服器如何獲取sessionId的呢?後臺用的伺服器是Tomcat,它在處理http請求時會解析請求訊息頭,從中獲取sessionId,然後獲取session物件,這也許是如上方法嘗試失敗的原因吧。
如上不可行後,又試想能不能繼續用這種方式,我在要返回的頁面把這個傳過來的sessionId給當作請求引數獲取,然後通過sessionId獲取session,覺得這個想法似乎不錯,很快就發現有阻力了(°ο°)Servlet2.1之後不支援SessionContext裡面getSession(String id)方法。。。但是可以通過HttpSessionListener監聽器和全域性靜態map自己實現一個SessionContext,到這裡開始覺得自己的思路不對,我獲取這個session之後呢。。。
接著怎麼辦呢,請求訊息頭是沒辦法改了,如何讓請求訊息頭中帶上cookie呢?在思考無效之後請教了身邊大神,大神告訴我,你的return_url是用的花生殼的對映地址,類似http://a0167495a2.imtodk.net:11236/buy這種格式的url,而調支付介面之前的訪問url都是http://localhost.8080/buy這種格式的url,所以導致session失效,真是一語驚醒夢中人啊,將域名埠改成一樣之後,果然解決了。
分析為什麼會這樣呢,這是個cookie路徑問題,瀏覽器在訪問伺服器上的某個地址時,會比較cookie的路徑與改路徑是否匹配,只有匹配的cookie才會傳送給伺服器,上面那兩個路徑怎麼看都匹配不上,所以請求訊息頭中當然沒有sessionId了,伺服器也就獲取不到session了。
ps:其實這個問題很傻,可是也廢了兩天時間,重要的是思考的過程,記錄一下。