首頁 > 軟體

React專案中fetch實現跨域接收傳遞session的解決方案

2022-04-20 19:00:44

本次專案使用了react框架,同時使用fetch取代ajax作為獲取介面資料的互動方法。本以為過程中應該不會有什麼磕絆,沒想到遇到了session丟失這個讓人甚是苦惱的問題。期間本想換種方法來對接介面,但轉念一想如果每次遇到問題都選擇逃避,那麼以後的編碼之路只能越走越窄,所以還是決定堅持下去。好在經過一整天的摸索,總算是成功攻克了這個難關,下面就對這次問題的解決做個總結。

首先,為什麼會出現postman介面偵錯正常而程式裡fetch呼叫卻出現session丟失的問題?

回顧fetch本身的特性——預設情況下, fetch在伺服器端不會傳送或接收任何 cookies!!

再來看session——當用戶端第一次請求伺服器的時候,伺服器生成一份session儲存在伺服器端,將該資料(session)的id以cookie的形式傳遞給使用者端;以後的每次請求,瀏覽器都會自動的攜帶cookie來存取伺服器(session資料id)。

這就意味著fetch這種方法如果想要攜帶cookie,需要經過特殊的處理——credentials: "include",程式碼如下:

fetch("https://ip:埠/api/Values/GetVerifyCode", {

            method: "GET",
            credentials: 'include',
            mode: 'cors',
            headers: {
                'Content-Type': 'application/json'
            }
        }).then(res => res.json())
            .then(res => {
                if (res.code == 200) {
                    //xxxxxxx
                }
            });

這裡還涉及到前後臺分離時經常遇到的跨域問題(mode: 'cors'),什麼是跨域?瀏覽器從一個域名的網頁去請求另一個域名的資源時,域名、埠、協定任一不同,都是跨域。在前後端分離的模式下,前後端的域名是不一致的,此時就會發生跨域存取問題。在請求的過程中我們要想回去資料一般都是post/get請求,所以..跨域問題就出現。這是出於瀏覽器的同源策略限制。(節選自https://zhuanlan.zhihu.com/p/425855609

後臺以.netcore webapi為例,需要在Startup.cs裡設定好Cors,程式碼如下:

ConfigureServices裡:

services.AddCors(options =>

            {
                options.AddPolicy("any", builder =>
                {
                    builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
                });//跨域請求
            });

Configure裡:

app.UseCors("any");//跨域請求

這裡要注意的是如果你在伺服器端的web.config裡已經設定過跨域相關引數了,這裡在加的話程式執行時會報錯(”*,*”…意思就是重複設定跨域引數),要使用credentials: 'include',需要將上面的允許來自所有域的跨域請求存取改為只允許特定域存取,同時允許Credentials,如下:

services.AddCors(options =>

            {
                options.AddPolicy("any", builder =>
                {
                    builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
                });//跨域請求
            });

本來進行到這裡我以為問題已經解決了,在本地偵錯OK的情況下發布介面,然後呼叫釋出好的伺服器介面,卻還是沒有獲取到想要的cookie。以驗證碼為例:一個fetch1生成驗證碼,並把它通過響應檔頭帶回來,之後另一個fetch2調介面時把之前帶回來的cookie再通過請求檔頭傳到後臺進行校驗,開啟控制檯發現fetch2的請求檔頭並沒有cookie值,而fetch1的響應檔頭裡也沒有Set-Cookie。

點開末尾的cookie才發現問題的所在:

這個SameSite是何許人也?

SameSite是瀏覽器請求中Set-Cookie響應頭新增的一種屬性,它用來標明這個 cookie 是否是“同站 cookie”,同站 cookie 只能在本域名中使用的cookie,不能作為第三方 cookie。Chrome 51 開始,瀏覽器的 Cookie 新增加了一個SameSite屬性,用來防止 CSRF 攻擊和使用者追蹤。該屬性起初是由Google 起草的一份草案用來來改進 HTTP 協定的。Chrome 計劃將Lax變為預設設定。這時,網站可以選擇顯式關閉SameSite屬性,將其設為None (對舊版瀏覽器無效,因為舊版瀏覽器沒有該值) 。不過,前提是必須同時設定Secure屬性(Cookie 只能通過 HTTPS 協定傳送),否則無效。(節選自https://www.cnblogs.com/w821759016/p/14595832.html

瞭解了這個,便可以很快地對Startup.cs裡的services.AddSession做出調整,如下:

services.AddSession(options =>

            {
                options.Cookie.Name = ".AdventureWorks.Session";
                options.IdleTimeout = TimeSpan.FromSeconds(1800);//設定session的過期時間
                options.Cookie.HttpOnly = true;//設定在瀏覽器不能通過js獲得該cookie的值
                options.Cookie.SameSite = SameSiteMode.None;
                options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                options.Cookie.IsEssential = true;
            });

其中,SameSite設為None配合Secure設為SameAsRequest,但要注意這個只允許存取的介面為https介面,另外將SameSite設定為了Unspecified瀏覽器則會使用預設值lax,是沒有效果的。

最後,將原先的http介面改為https,至於https認證所需的SSL證書怎麼搞這裡就不贅述了,將這些完成後再次嘗試呼叫釋出好的介面,fetch1裡的響應檔頭以及fetch2裡的請求檔頭就都能在控制檯看見了,問題解決!

到此這篇關於React專案中fetch實現跨域接收傳遞session的解決方案的文章就介紹到這了,更多相關react fetch跨域接收傳遞session內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com