前言:上篇總結了下WebApi的介面測試工具的使用,這篇接著來看看WebAPI的另一個常見問題:跨域問題。本篇主要從例項的角度分享下CORS解決跨域問題一些細節。
一、跨域問題的由來
同源策略:出於安全考慮,瀏覽器會限制指令碼中發起的跨站請求,瀏覽器要求JavaScript或Cookie只能訪問同域下的內容。
正是由於這個原因,我們不同專案之間的呼叫就會被瀏覽器阻止。比如我們最常見的場景:WebApi作為資料服務層,它是一個單獨的專案,我們的MVC專案作為Web的顯示層,這個時候我們的MVC裡面就需要呼叫WebApi裡面的介面取資料展現在頁面上。因為我們的WebApi和MVC是兩個不同的專案,所以執行起來之後就存在上面說的跨域的問題。
二、跨域問題解決原理
CORS全稱Cross-Origin Resource Sharing,中文全稱跨域資源共享。它解決跨域問題的原理是通過向http的請求報文和響應報文裡面加入相應的標識告訴瀏覽器它能訪問哪些域名的請求。比如我們向響應報文裡面增加這個Access-Control-Allow-Origin:http://localhost:8081,就表示支援http://localhost:8081裡面的所有請求訪問系統資源。其他更多的應用我們就不一一列舉,可以去網上找找。
三、跨域問題解決細節
下面我就結合一個簡單的例項來說明下如何使用CORS解決WebApi的跨域問題。
1、場景描述
我們新建兩個專案,一個WebApi專案(下圖中WebApiCORS),一個MVC專案(下圖中Web)。WebApi專案負責提供介面服務,MVC專案負責頁面呈現。如下:
其中,Web與WebApiCORS埠號分別為“27239”和“27221”。Web專案需要從WebApiCORSS專案裡面取資料,很顯然,兩個專案埠不同,所以並不同源,如果使用常規的呼叫方法肯定存在一個跨域的問題。
簡單介紹下測試程式碼,Web裡面有一個HomeController
1 2 3 4 5 6 7 8 |
public class HomeController : Controller { // GET: Home public ActionResult Index() { return View(); } } |
對應的Index.cshtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="~/Content/jquery-1.9.1.js"></script> <link href="~/Content/bootstrap/css/bootstrap.css" rel="stylesheet" /> <script src="~/Content/bootstrap/js/bootstrap.js"></script> <script src="~/Scripts/Home/Index.js"></script> </head> <body> 測試結果:<div id="div_test"> </div> </body> </html> |
Index.js檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var ApiUrl = "http://localhost:27221/"; $(function () { $.ajax({ type: "get", url: ApiUrl + "api/Charging/GetAllChargingData", data: {}, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); }, complete: function () { } }); }); |
WebApiCORS專案裡面有一個測試的WebApi服務ChargingController
1 2 3 4 5 6 7 8 9 10 11 12 |
public class ChargingController : ApiController { /// /// 得到所有資料 /// /// 返回資料 [HttpGet] public string GetAllChargingData() { return "Success"; } } |
配置WebApi的路由規則為通過action呼叫。WebApiConfig.cs檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } } |
2、場景測試
1)我們不做任何的處理,直接將兩個專案執行起來。看效果如何
IE瀏覽器:
谷歌瀏覽器:
這個結果另博主也很吃驚,不做任何跨域處理,IE10、IE11竟然可以直接請求資料成功,而同樣的程式碼IE8、IE9、谷歌瀏覽器卻不能跨域訪問。此原因有待查詢,應該是微軟動了什麼手腳。
2)使用CORS跨域
首先介紹下CORS如何使用,在WebApiCORS專案上面使用Nuget搜尋“microsoft.aspnet.webapi.cors”,安裝第一個
然後在App_Start資料夾下面的WebApiConfig.cs資料夾配置跨域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public static class WebApiConfig { public static void Register(HttpConfiguration config) { //跨域配置 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } } |
我們暫定三個“*”號,當然,在專案中使用的時候一般需要指定對哪個域名可以跨域、跨域的操作有哪些等等。這個在下面介紹。
IE10、IE11
谷歌瀏覽器
IE8、IE9
這個時候又有新問題了,怎麼回事呢?我都已經設定跨域了呀,怎麼IE8、9還是不行呢?這個時候就有必要說說CORS的瀏覽器支援問題了。網上到處都能搜到這張圖:
上圖描述了CORS的瀏覽器支援情況,可以看到IE8、9是部分支援的。網上說的解決方案都是Internet Explorer 8 、9使用 XDomainRequest 物件實現CORS。是不是有這麼複雜?於是博主各種百度尋找解決方案。最後發現在呼叫處指定 jQuery.support.cors = true; 這一句就能解決IE8、9的問題了。具體是在Index.js裡面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
jQuery.support.cors = true; var ApiUrl = "http://localhost:27221/"; $(function () { $.ajax({ type: "get", url: ApiUrl + "api/Charging/GetAllChargingData", data: {}, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); }, complete: function () { } }); }); |
這句話的意思就是指定瀏覽器支援跨域。原來IE9以上版本的瀏覽器、谷歌、火狐等都預設支援跨域,而IE8、9卻預設不支援跨域,需要我們指定一下。你可以在你的瀏覽器裡面列印jQuery.support.cors看看。這樣設定之後是否能解決問題呢?我們來看效果:
問題完美解決。至於網上說的CORS對IE8、9的解決方案XDomainRequest是怎麼回事,有待例項驗證。
3)CORS的具體引數設定。
上文我們使用
1 |
config.EnableCors(new EnableCorsAttribute("*", "*", "*")); |
這一句解決了跨域問題,上面說了,這種*號是不安全的。因為它表示只要別人知道了你的請求url,任何請求都可以訪問到你的資源。這是相當危險的。所以需要我們做一些配置,限制訪問許可權。比如我們比較常見的做法如下:
配置方法一、在Web.Config裡面(PS:這兩張圖源自:http://www.cnblogs.com/moretry/p/4154479.html)
然後在WebApiConfig.cs檔案的Register方法裡面
配置方法二、如果你只想對某一些api做跨域,可以直接在API的類上面使用特性標註即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[EnableCors(origins: "http://localhost:8081/", headers: "*", methods: "GET,POST,PUT,DELETE")] public class ChargingController : ApiController { /// /// 得到所有資料 /// /// 返回資料 [HttpGet] public string GetAllChargingData() { return "Success"; } } |
四、總結
以上就是一個簡單的CORS解決WebApi跨域問題的例項,由於博主使用WebApi的時間並不長,所以很多理論觀點未必成熟,如果有說的不對的,歡迎指出。
WebAPI系列文章: