我們都知道許多瀏覽器基於安全方面的考量,會禁止瀏覽器透過 AJAX 來存取外部網站,這也代表著如果我們利用 Web API 寫了一個 Service 想要提供給使用者來使用,使用者無法從其網站來取的你的 Web API 。話雖如此,在 ASP.NET Web API 中只要透過屬性的設定就可以讓我們的 Web Service 支援 CORS(跨來源資源共享) 。
前言
我們都知道許多瀏覽器基於安全方面的考量,會禁止瀏覽器透過 AJAX 來存取外部網站,這也代表著如果我們利用 Web API 寫了一個 Service 想要提供給使用者來使用,使用者無法從其網站來取的你的 Web API 。話雖如此,在 ASP.NET Web API 中只要透過屬性的設定就可以讓我們的 Web Service 支援 CORS(跨來源資源共享) 。
什麼是 CORS(跨來源資源共享)
就像我們前面說到的,CORS 代表跨來源資源共享,CORS 為 W3C 所訂定的一個標準,簡單來說就是可讓 A 網域向 B 網域發出跨網域的 AJAX 請求。
舉個範例,假設我們有兩個網址,且來自兩台不同的主機,分別為:
http://www.website1.com
http://www.website2.com
也因為他們來自於不同的主機,它們會被瀏覽器認定為來自不同的來源,或是在這種情況下: http://www.website.com 和 https://www.website.com 這兩個網址還是屬於不同的來源,因為他們的協定是不同的。
假設我們今天開發了一個 ASP.NET Web API 的 Web Services ,這個 Service 的主機名稱為 www.website1.com (稱A),同時我們也開發另外一個網站主機名稱為 www.website2.com (稱B),然而假設 B 網站存取 A 網站的 Web API ,所以我們使用 XMLRequest 或 jQuery 的 $.ajax 來呼叫我們的 Web API ,不幸的是這樣的溝通是會出錯的,因為瀏覽器不允許使用 AJAX 來呼叫外部的資源。
不過雖然瀏覽器為了安全起見阻止此類的呼叫,不過假設我們今天的請求是合法的呢?CORS 則規範了一種標準方式,來允許此類安全的呼叫,所以我們可以使用 CORS 來達到跨來源的請求,這樣就可以解決 B 網站利用 AJAX 來請求在 A 網站的 Web API 服務了。
Oh !請求發生錯誤了
接下來為了讓讀者更明白這個問題,所以筆者這邊舉一個簡單的例子來示範問題如何發生的,首先我們先建立兩個專案,以下稱專案A與專案B,專案A我們用來提供 Web API 的服務,我們就已 ASP.NET Web API 預設為我們建立的 ValuesController 範本為例:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable Get()
{
return new string[] { "value1", "value2" };
}
}
然後我們將網站 Run 起來,以筆者的為例,網址為 http://localhost:55041,接著我們在建立專案B,並且在 HomeController 底下新增一個檢視(View)命名為 CORS,並在 View 新增下面 jQuery 程式碼片段:
<script>
$(function () {
$.getJSON("http://localhost:55041/api/Values", function () {
alert("Acces");
});
});
</script>
接著我們將 B 專案也 Run 起來,網址為 http://localhost:59776,當我們進入 /Home/CORS 時,使用Chrome的開發者工具應該會看到這個錯誤,如下:
從錯誤訊息中我們可以清楚看到 XMLHttpRequest 調用失敗,並且明確寫著來源不允許請求 "Access-Control-Allow-Origin",而什麼是 "Access-Control-Allow-Origin":當每次網頁伺服器在回應瀏覽器請求時,而當 HTTP Header 中有時會帶有 "Access-Control-Allow-Origin" 時,就可以做到跨網域的請求。
如何解決?
呼~比較簡單的作法就是在 web.config 中加入 "Access-Control-Allow-Origin" ,所以我們打開 web.config 的檔案,在 <system.webServer> 添加下列片段:
<system.webserver>
<httpprotocol>
<customheaders>
<add name="Access-Control-Allow-Origin" value="*">
</add></customheaders>
</httpprotocol>
</system.webserver>
這個作法就是讓我們在 HTTP 的 Header 新增一個 "Access-Control-Allow-Origin" 屬性且 Value 為 "*",代表允許所有的來源,這時我們專案 A 這個 Web API 就已經啟用了 CORS ,所以你在重新執行一次,你會發現就不會發生錯誤了,而回傳的 Header 也有我們剛剛自定的 "Access-Control-Allow-Origin":
當然在 web.config 這個設定的作法比較簡單,但還是存在著風險,因為這樣的設定可以讓全世界的網站都可以來存取你這個網站的所有 Web API,就算是 Google 或 Facebook 也不可能公開所有的 API 來讓一般使用者存取,所以若我們希望某些特定的 API 開放某些維持現狀,可以透過第二種解法(總結之後)。
總結
當然要解決瀏覽器跨網域的問題處理利用 CORS 以外,另外還有像是 JSONP(JSON With Padding),為 JSON 的一種使用模式,可以讓網頁從別的網域來取得資料,透過在送出的網址後面加上?calback 的方式已達到跨網域需求,但這個做法是屬於前端的 jQuery 設定的,而這篇介紹到的 CORS 是屬於 W3C 訂定的一種規範,至於 JSONP 的介紹待後續筆者有時間會在將作法補上,嗚嗚嗚!其實不知道該說什麼了,當勇者先鋒的結局就是慘慘慘...。
最後更新:2013/5/22
針對小弟碰到的問題,小朱前輩已經有解答了,先前我也試著移除過語言套件似乎也無法啟作用,應該說移除掉語言套件然後又會出別的錯誤,今天小弟在整理一下在補上後續的動作,有興趣的朋友可以先看看小朱前輩的貼文。
[ASP.NET][Web API] 使用 ASP.NET Web API CORS 功能 (Beta Preview) 的前置作業
最後更新:2013/05/19
不知道是不是因為第二種解法要安裝的套件還不是很穩定,筆者在安裝時頻頻出現這個錯誤,導致無法安裝成功,所以只能暫時終止後續的介紹了(殘念),不過這篇文章是參考國外 MVP寫的,如果有興趣的讀者也可以到這邊來看原作者的說明 Using Cross Origin Resource Sharing (CORS) in ASP.NET Web API ,若待後續版本比較穩定,這邊文章會在持續更新。
第二種解決方法就是透過 NuGet 來新增 Microsoft ASP.NET Web API Cross Origin 這個套件,而此套件目前還是屬於 Nighty Builds 的版本,算是還在開發階段僅提供給開發人員測試的版本,所以可能還不是很穩定或是有安全性的漏洞,但後續在 Web API 應該也會支持這個套件。
1.首先我們需要先到 Visul Studio 裡新增套件來源,如下:
2.透過 Nuget 安裝 Microsoft ASP.NET Web API Cross-Origin
錯誤畫面:
新手發文,如有錯誤煩請告知,感謝。
如果喜歡我的文章請按推薦,有任何問題歡迎下面留言~~~
簽名:
學習這條路很廣,喜歡什麼技術不重要,重要的是你肯花時間去學習