1. 程式人生 > >關於Ajax跨域提交時session丟失的問題

關於Ajax跨域提交時session丟失的問題

今天在工作中遇到了一個問題,就是當使用ajax和jsonp進行跨域時,每一伺服器都會在cookie裡set一個新的sessionId,會將原有的sessionId覆蓋,也就是說客戶端對於伺服器來說始終處於未登入狀態,我使用谷歌瀏覽器是沒有問題的,但是IE有問題,在ie出問題的原因是瀏覽器中的cookie值在ajax跨域提交時沒有帶過去,就會造成伺服器獲取不到cookie中的sessionId,效果就是伺服器在每次跨域返回值得時候自動建立一個新的sessionId,知道了原因,下面說說解決方法:

第一種:簡單粗暴型

調整客戶端瀏覽器的internet選項,選擇隱私,設定接受所有cookie

這裡寫圖片描述

當然這種不適合那種有很多客戶端的場景,總不能每臺機器都是手動調吧

第二種: 使用 P3P 規範讓 IE 跨域接受第三方 cookie

瀏覽器的第三方 cookie 限制

所謂第三方 cookie,就是說你訪問域名A下的網頁,卻接收到域名 B 的 cookie 設定指令。這可能是由於網頁 A 請求或連結了 B 的網頁,比如上面提到的jsonp。

我查到了各個瀏覽器對於跨域的處理規則,可以看到第三方 cookie ,IE 在預設設定中是做了限制的。

這裡寫圖片描述

所以要解決這個問題,除了修改瀏覽器設定,就要使用P3P

P3P是一種被稱為個人隱私安全平臺專案(the Platform for Privacy Preferences)的標準,能夠保護線上隱私權,就是網站向瀏覽器宣告自己的隱私政策,比如網站是否蒐集訪問者的個人資訊,設定 cookie 的用途等等。瀏覽器會依據設定,決定在第三方請求的條件下是否接受網站的 cookie。

所以我就在伺服器返回資料時,添加了如下語句

response.setHeader("P3P","CP=CAO PSA OUR");

搞定!

還有一種我沒有試過,但是也是一種解決辦法,在此也記錄一下,這個用的就是json+ajax,使用的標準是CORS,即跨域資源共享。

CORS是一個W3C標準,全稱是”跨域資源共享”(Cross-origin resource sharing)。

它允許瀏覽器向跨源伺服器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

CORS需要瀏覽器和伺服器同時支援。目前,所有瀏覽器都支援該功能,IE瀏覽器不能低於IE10。

首先我們需要構建一個攔截器

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

 

//新增跨域驗證
String origin = response.getHeader("Access-Control-Allow-Origin");
if (!"*".equals(origin)) {
    response.addHeader("Access-Control-Allow-Origin", "*");
}

HttpServletResponse res = (HttpServletResponse) servletResponse;

HttpServletRequest request=(HttpServletRequest)servletRequest;

res.setContentType("textml;charset=UTF-8");

res.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

res.setHeader("Access-Control-Max-Age", "0");

res.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");

res.setHeader("Access-Control-Allow-Credentials", "true");

res.setHeader("XDomainRequestAllowed","1");

filterChain.doFilter(servletRequest,servletResponse);

}

將指定請求攔截下來後新增header

(1)Access-Control-Allow-Origin

該欄位是必須的。它的值要麼是請求時Origin欄位的值,要麼是一個*,表示接受任意域名的請求。

(2)Access-Control-Allow-Credentials

該欄位可選。它的值是一個布林值,表示是否允許傳送Cookie。預設情況下,Cookie不包括在CORS請求之中。設為true,即表示伺服器明確許可,Cookie可以包含在請求中,一起發給伺服器。這個值也只能設為true,如果伺服器不要瀏覽器傳送Cookie,刪除該欄位即可。

(3)Access-Control-Expose-Headers

該欄位可選。CORS請求時,XMLHttpRequest物件的getResponseHeader()方法只能拿到6個基本欄位:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他欄位,就必須在Access-Control-Expose-Headers裡面指定。上面的例子指定,getResponseHeader(‘FooBar’)可以返回FooBar欄位的值。

然後在前臺js進行修改:

$.ajax({

url:url,

//加上這句話

xhrFields: {

withCredentials: true

},

crossDomain: true,

//

success:function(result){

alert(“test”);

},

error:function(){

}

});

這樣我們再跨域測試的時候,就會發現我們的sessionId是一樣的了,這樣就實現了跨域並且保證在同一個session下。

參考資料:

https://www.ruanyifeng.com/blog/2016/04/cors.html

https://www.2cto.com/kf/201708/672857.html