1, 什么是跨域
瀏覽器從一個域名的網頁去請求另一個域名的資源時,域名、端口、協議任一不同,都是跨域
域名:
主域名不同 http://www.baidu.com/index.html -->http://www.sina.com/test.js
子域名不同 http://www.666.baidu.com/index.html -->http://www.555.baidu.com/test.js
域名和域名ip http://www.baidu.com/index.html -->http://180.149.132.47/test.js
端口:
http://www.baidu.com:8080/index.html–> http://www.baidu.com:8081/test.js
協議:
http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js
備注:
1、端口和協議的不同,只能通過后台來解決
2、localhost和127.0.0.1雖然都指向本機,但也屬於跨域
當發生跨域訪問(cross-domain access),瀏覽器就無法正常從后台服務中獲取信息。所以必須要解決跨域問題。
2,跨域的種類
瀏覽器將CORS請求分成兩類:簡單請求(simple request)
和非簡單請求(not-so-simple request
)。
只要同時滿足以下兩大條件,就屬於簡單請求。
(1) 請求方法是以下三種方法之一: HEAD GET POST (2)HTTP的頭信息不超出以下幾種字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限於三個值 application/x-www-form-urlencoded(對發送內容進行編碼) multipart/form-data(上傳的表單內包含文件) text/plain(發送內容為純文本格式)
凡是不同時滿足上面兩個條件,就屬於非簡單請求。
對於簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在頭信息之中,增加一個Origin
字段。
Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0…
上面的頭信息中,Origin
字段用來說明,本次請求來自哪個源(協議 + 域名 + 端口)。服務器根據這個值,再根據自身的跨域設置,決定是否同意這次請求。
如果Origin
指定的源,不在許可范圍內,服務器會返回一個正常的HTTP回應。瀏覽器發現,這個回應的頭信息沒有包含Access-Control-Allow-Origin
字段(詳見下文),就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest
的onerror
回調函數捕獲。注意,這種錯誤無法通過狀態碼識別,因為HTTP回應的狀態碼有可能是200。
對於非簡單請求的CORS請求,會在正式通信之前,不需要用戶操作,瀏覽器自動發送一個OPTION請求(也叫做預檢操作)。
服務器收到預檢請求后,檢查這些特殊的請求方法和頭自己能否接受。如果服務器支持預檢中的Header和Methods,那么接下來就可以正常發送信息。
3,跨域的解決方案
跨域問題可以從三個方面着手解決:前端/后端/網關
前端很多的解決方案,例如Vue的話可以試試:axios解決跨域問題(vue-cli3.0)
.Net Core 3.1 的后端的解決方法也比較簡單,最懶的方法是在Startup.cs的Configure方法增加以下代碼:
app.UseCors(builder => { builder.AllowAnyMethod() .AllowAnyHeader() .SetIsOriginAllowed(_ => true) // =AllowAnyOrigin() .AllowCredentials(); });
將上述代碼插入到 app.UseRouting() 與 app.UseCors之間,則在全局范圍內取消了一切跨域訪問的限制。
或者,在ConfigureServices方法添加跨域設置,然后在Configure方法使用這個跨域設置也可以:
//ConfigureServices 設置允許所有來源跨域 services.AddCors(options => options.AddPolicy("CorsPolicy", builder => { builder.AllowAnyMethod() .AllowAnyHeader() .SetIsOriginAllowed(_ => true) // =AllowAnyOrigin() .AllowCredentials(); })); //Configure 使用跨域配置 app.UseCors("CorsPolicy");
如果不想全局都一個跨域的設置,而是每一個Controller設置每一個方法都有特定的跨域設置,則可以在Startup.cs文件的方法用AddCors方法添加若干個跨域設置,然后在對應的Controller或者方法上使用 [EnableCors] 屬性啟用 CORS。
詳情可以參考微軟官方文檔:在 ASP.NET Core 中啟用跨源請求 (CORS)
對於后台服務來說,一般都要配備網關。我這個項目選用了國人開源的Apisix網關。Apisix的使用就不啰嗦了,反正友好的文檔以及方便的Dashboard,相當的不錯。
前面說過,跨域請求的“非簡單請求”會首先發送一次OPTION請求(預檢操作)到服務器,等待服務器告知正常才正式執行請求。所以,務必務必,在網關設置允許的HTTP方法里,添加選擇OPTION
如果后端已經開啟了CORS,則網關除了HTTP方法外無需留意其他的設置。但如果后端不設置的話,網關也一樣能解決跨域訪問:
我們在Apisix網關的路由配置頁面的第三步“插件配置”里可以發現一個Cors,只需要將其啟用即可:
相關的配置,Apisix也有詳細的文檔說明:cors
4,參考鏈接: