假設使用 ASP.NET Core 6 建立了一個 API , 連結為 http://localhost:8080/user ,使用 Post 方法,需要在 Body 中帶入資料,在 Postman 中可以正常呼叫和取得回應,但是在別的網站上無法呼叫,在瀏覽器的開發人員工具的主控台中出現了下面的錯誤:
Firefox 錯誤訊息:
Chrome 錯誤訊息:
CORS 是一個 Web 標準,用來限制瀏覽器從不同來源請求資源,只要瀏覽器檢查到不同來源的資源請求,就會進行檢查,確保使用者的資料安全。若該請求不為簡單請求(simple requests),則會觸發 CORS 預檢,發送一個 OPTIONS 請求,稱為預檢請求(Preflight Request),驗證伺服器回應的訊息中是否包含 Access-Control-Allow-Origin (所以瀏覽器中才會有兩個錯誤),由此確認伺服器是否允許本網頁跨來源請求資源。如果預檢請求沒有通過,確認目標伺服器拒絕本網頁跨來源請求資源,則不會發送原本請求。
而 Postman 不是瀏覽器,不受 CORS 策略的限制,所以使用 Postman 沒有 CORS 問題,不代表就沒有 CORS 問題,因為這個問題是瀏覽器為了安全而限制的。
所以通常遇到 CORS 問題時,不是呼叫 API 的客戶端(如網頁)的問題,而是伺服器端的問題(如 ASP.NET Core),前端工程師可以鬆一口氣,直接把問題甩到後端工程師身上(誤)。
或是要設定只能允許幾個來源,可以將第六行替換,就可以以白名單的形式設定
最後在 UseRouting 後面和 UseEndpoints 前面加入 UseCors 即可,程式碼如下:
若沒有 UseEndpoints 則加在 builder.Build() 的後方就可以了。
再次重新發送請求時就不會再出現 CORS 錯誤了!
參考資料:
mdn.docs - 跨來源資源共用(CORS)
StackOverflow - Access Control Origin Header error using Axios
StackOverflow - POSTing to external API throws CORS but it works from Postman
Microsoft.Learn - Enable Cross-Origin Requests (CORS) in ASP.NET Core
Firefox 錯誤訊息:
已封鎖跨來源請求: 同源政策不允許讀取 http://localhost:8080/user 的遠端資源。(原因: 缺少 CORS 'Access-Control-Allow-Origin' 檔頭)。狀態代碼: 302。
已封鎖跨來源請求: 同源政策不允許讀取 http://localhost:8080/user 的遠端資源。(原因: CORS 請求未成功)。狀態代碼: (null)。
Chrome 錯誤訊息:
POSThttp://localhost:8080/user net::ERR_FAILED
Access to XMLHttpRequest at 'http://localhost:8080/user' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
CORS 是什麼?
依據 mdn 上的說法, CORS(Cross-Origin Resource Sharing) 是跨來源資源共用,只要網域(domain)、通訊協定(protocol)或通訊埠(port) 不同時,就會產生跨來源 HTTP 請求(cross-origin HTTP request)。CORS 是一個 Web 標準,用來限制瀏覽器從不同來源請求資源,只要瀏覽器檢查到不同來源的資源請求,就會進行檢查,確保使用者的資料安全。若該請求不為簡單請求(simple requests),則會觸發 CORS 預檢,發送一個 OPTIONS 請求,稱為預檢請求(Preflight Request),驗證伺服器回應的訊息中是否包含 Access-Control-Allow-Origin (所以瀏覽器中才會有兩個錯誤),由此確認伺服器是否允許本網頁跨來源請求資源。如果預檢請求沒有通過,確認目標伺服器拒絕本網頁跨來源請求資源,則不會發送原本請求。
而 Postman 不是瀏覽器,不受 CORS 策略的限制,所以使用 Postman 沒有 CORS 問題,不代表就沒有 CORS 問題,因為這個問題是瀏覽器為了安全而限制的。
所以通常遇到 CORS 問題時,不是呼叫 API 的客戶端(如網頁)的問題,而是伺服器端的問題(如 ASP.NET Core),前端工程師可以鬆一口氣,直接把問題甩到後端工程師身上(誤)。
ASP.NET Core 6 解決 CORS 的方式
在 var app = builder.Build(); 前加入下面的程式碼:
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.AllowAnyOrigin() // 允許任何來源
.AllowAnyMethod()
.AllowAnyHeader();
});
});
或是要設定只能允許幾個來源,可以將第六行替換,就可以以白名單的形式設定
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins("http://localhost:5173", "https://localhost:44300") // 只允許這兩個來源
.AllowAnyMethod()
.AllowAnyHeader();
});
});
最後在 UseRouting 後面和 UseEndpoints 前面加入 UseCors 即可,程式碼如下:
var app = builder.Build();
app.UseRouting();
app.UseCors();
app.UseEndpoints();
若沒有 UseEndpoints 則加在 builder.Build() 的後方就可以了。
再次重新發送請求時就不會再出現 CORS 錯誤了!
參考資料:
mdn.docs - 跨來源資源共用(CORS)
StackOverflow - Access Control Origin Header error using Axios
StackOverflow - POSTing to external API throws CORS but it works from Postman
Microsoft.Learn - Enable Cross-Origin Requests (CORS) in ASP.NET Core
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com