C# WebApi CORS跨域問(wèn)題解決方案
前言:上篇總結(jié)了下WebApi的接口測(cè)試工具的使用,這篇接著來(lái)看看WebAPI的另一個(gè)常見(jiàn)問(wèn)題:跨域問(wèn)題。本篇主要從實(shí)例的角度分享下CORS解決跨域問(wèn)題一些細(xì)節(jié)。
一、跨域問(wèn)題的由來(lái)
同源策略:出于安全考慮,瀏覽器會(huì)限制腳本中發(fā)起的跨站請(qǐng)求,瀏覽器要求JavaScript或Cookie只能訪問(wèn)同域下的內(nèi)容。
正是由于這個(gè)原因,我們不同項(xiàng)目之間的調(diào)用就會(huì)被瀏覽器阻止。比如我們最常見(jiàn)的場(chǎng)景:WebApi作為數(shù)據(jù)服務(wù)層,它是一個(gè)單獨(dú)的項(xiàng)目,我們的MVC項(xiàng)目作為Web的顯示層,這個(gè)時(shí)候我們的MVC里面就需要調(diào)用WebApi里面的接口取數(shù)據(jù)展現(xiàn)在頁(yè)面上。因?yàn)槲覀兊腤ebApi和MVC是兩個(gè)不同的項(xiàng)目,所以運(yùn)行起來(lái)之后就存在上面說(shuō)的跨域的問(wèn)題。
二、跨域問(wèn)題解決原理
CORS全稱Cross-Origin Resource Sharing,中文全稱跨域資源共享。它解決跨域問(wèn)題的原理是通過(guò)向http的請(qǐng)求報(bào)文和響應(yīng)報(bào)文里面加入相應(yīng)的標(biāo)識(shí)告訴瀏覽器它能訪問(wèn)哪些域名的請(qǐng)求。比如我們向響應(yīng)報(bào)文里面增加這個(gè)Access-Control-Allow-Origin:http://localhost:8081,就表示支持http://localhost:8081里面的所有請(qǐng)求訪問(wèn)系統(tǒng)資源。其他更多的應(yīng)用我們就不一一列舉,可以去網(wǎng)上找找。
三、跨域問(wèn)題解決細(xì)節(jié)
下面我就結(jié)合一個(gè)簡(jiǎn)單的實(shí)例來(lái)說(shuō)明下如何使用CORS解決WebApi的跨域問(wèn)題。
1、場(chǎng)景描述
我們新建兩個(gè)項(xiàng)目,一個(gè)WebApi項(xiàng)目(下圖中WebApiCORS),一個(gè)MVC項(xiàng)目(下圖中Web)。WebApi項(xiàng)目負(fù)責(zé)提供接口服務(wù),MVC項(xiàng)目負(fù)責(zé)頁(yè)面呈現(xiàn)。如下:

其中,Web與WebApiCORS端口號(hào)分別為“27239”和“27221”。Web項(xiàng)目需要從WebApiCORSS項(xiàng)目里面取數(shù)據(jù),很顯然,兩個(gè)項(xiàng)目端口不同,所以并不同源,如果使用常規(guī)的調(diào)用方法肯定存在一個(gè)跨域的問(wèn)題。
簡(jiǎn)單介紹下測(cè)試代碼,Web里面有一個(gè)HomeController
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
}
對(duì)應(yīng)的Index.cshtml
<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="external nofollow" rel="stylesheet" /> <script src="~/Content/bootstrap/js/bootstrap.js"></script> <script src="~/Scripts/Home/Index.js"></script> </head> <body> 測(cè)試結(jié)果:<div id="div_test"> </div> </body> </html>
Index.js文件
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項(xiàng)目里面有一個(gè)測(cè)試的WebApi服務(wù)ChargingController
public class ChargingController : ApiController
{
/// <summary>
/// 得到所有數(shù)據(jù)
/// </summary>
/// <returns>返回?cái)?shù)據(jù)</returns>
[HttpGet]
public string GetAllChargingData()
{
return "Success";
}
}
配置WebApi的路由規(guī)則為通過(guò)action調(diào)用。WebApiConfig.cs文件
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、場(chǎng)景測(cè)試
1)我們不做任何的處理,直接將兩個(gè)項(xiàng)目運(yùn)行起來(lái)??葱Ч绾?/p>
IE瀏覽器:

谷歌瀏覽器:

這個(gè)結(jié)果另博主也很吃驚,不做任何跨域處理,IE10、IE11竟然可以直接請(qǐng)求數(shù)據(jù)成功,而同樣的代碼IE8、IE9、谷歌瀏覽器卻不能跨域訪問(wèn)。此原因有待查找,應(yīng)該是微軟動(dòng)了什么手腳。
2)使用CORS跨域
首先介紹下CORS如何使用,在WebApiCORS項(xiàng)目上面使用Nuget搜索“microsoft.aspnet.webapi.cors”,安裝第一個(gè)

然后在App_Start文件夾下面的WebApiConfig.cs文件夾配置跨域
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 }
);
}
}
我們暫定三個(gè)“*”號(hào),當(dāng)然,在項(xiàng)目中使用的時(shí)候一般需要指定對(duì)哪個(gè)域名可以跨域、跨域的操作有哪些等等。這個(gè)在下面介紹。
IE10、IE11

谷歌瀏覽器

IE8、IE9

這個(gè)時(shí)候又有新問(wèn)題了,怎么回事呢?我都已經(jīng)設(shè)置跨域了呀,怎么IE8、9還是不行呢?這個(gè)時(shí)候就有必要說(shuō)說(shuō)CORS的瀏覽器支持問(wèn)題了。網(wǎng)上到處都能搜到這張圖:

上圖描述了CORS的瀏覽器支持情況,可以看到IE8、9是部分支持的。網(wǎng)上說(shuō)的解決方案都是Internet Explorer 8、9使用 XDomainRequest對(duì)象實(shí)現(xiàn)CORS。是不是有這么復(fù)雜?于是博主各種百度尋找解決方案。最后發(fā)現(xiàn)在調(diào)用處指定jQuery.support.cors = true;這一句就能解決IE8、9的問(wèn)題了。具體是在Index.js里面
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 () {
}
});
});
這句話的意思就是指定瀏覽器支持跨域。原來(lái)IE9以上版本的瀏覽器、谷歌、火狐等都默認(rèn)支持跨域,而IE8、9卻默認(rèn)不支持跨域,需要我們指定一下。你可以在你的瀏覽器里面打印jQuery.support.cors看看。這樣設(shè)置之后是否能解決問(wèn)題呢?我們來(lái)看效果:

問(wèn)題完美解決。至于網(wǎng)上說(shuō)的CORS對(duì)IE8、9的解決方案XDomainRequest是怎么回事,有待實(shí)例驗(yàn)證。
3)CORS的具體參數(shù)設(shè)置。
上文我們使用
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
這一句解決了跨域問(wèn)題,上面說(shuō)了,這種*號(hào)是不安全的。因?yàn)樗硎局灰獎(jiǎng)e人知道了你的請(qǐng)求url,任何請(qǐng)求都可以訪問(wèn)到你的資源。這是相當(dāng)危險(xiǎn)的。所以需要我們做一些配置,限制訪問(wèn)權(quán)限。比如我們比較常見(jiàn)的做法如下:
配置方法一、在Web.Config里面

然后在WebApiConfig.cs文件的Register方法里面

配置方法二、如果你只想對(duì)某一些api做跨域,可以直接在API的類上面使用特性標(biāo)注即可。
[EnableCors(origins: "http://localhost:8081/", headers: "*", methods: "GET,POST,PUT,DELETE")]
public class ChargingController : ApiController
{
/// <summary>
/// 得到所有數(shù)據(jù)
/// </summary>
/// <returns>返回?cái)?shù)據(jù)</returns>
[HttpGet]
public string GetAllChargingData()
{
return "Success";
}
}
四、總結(jié)
以上就是一個(gè)簡(jiǎn)單的CORS解決WebApi跨域問(wèn)題的實(shí)例,由于博主使用WebApi的時(shí)間并不長(zhǎng),所以很多理論觀點(diǎn)未必成熟,如果有說(shuō)的不對(duì)的,歡迎指出。也希望大家多多支持腳本之家。
- Apache中配置支持CORS(跨域資源共享)實(shí)例
- JS跨域解決方案之使用CORS實(shí)現(xiàn)跨域
- js實(shí)現(xiàn)跨域的幾種方法匯總(圖片ping、JSONP和CORS)
- Node.js設(shè)置CORS跨域請(qǐng)求中多域名白名單的方法
- 淺談spring-boot 允許接口跨域并實(shí)現(xiàn)攔截(CORS)
- vue+springboot實(shí)現(xiàn)項(xiàng)目的CORS跨域請(qǐng)求
- 淺談Koa2框架利用CORS完成跨域ajax請(qǐng)求
- 跨域解決之JSONP和CORS的詳細(xì)介紹
- react中fetch之cors跨域請(qǐng)求的實(shí)現(xiàn)方法
- 跨域(CORS)問(wèn)題的解決方案分享
相關(guān)文章
C#畫(huà)筆Pen保存和恢復(fù)圖形對(duì)象的設(shè)置方法
這篇文章主要介紹了C#畫(huà)筆Pen保存和恢復(fù)圖形對(duì)象的設(shè)置方法,實(shí)例分析了畫(huà)筆的保存save及恢復(fù)屬性Restore的相關(guān)使用技巧,需要的朋友可以參考下2015-06-06
C#使用Parallel類進(jìn)行多線程編程實(shí)例
這篇文章主要介紹了C#使用Parallel類進(jìn)行多線程編程的方法,實(shí)例分析了Parallel類的相關(guān)使用技巧,需要的朋友可以參考下2015-06-06
C#實(shí)現(xiàn)帶百分比的進(jìn)度條功能示例
這篇文章主要介紹了C#實(shí)現(xiàn)帶百分比的進(jìn)度條功能,分析了帶百分比進(jìn)度條的功能需求并結(jié)合實(shí)例形式給出了具體實(shí)現(xiàn)步驟與相關(guān)操作方法,需要的朋友可以參考下2017-05-05
C#操作LINQ to SQL組件進(jìn)行數(shù)據(jù)庫(kù)建模的基本教程
這篇文章主要介紹了C#操作LINQ to SQL組件進(jìn)行數(shù)據(jù)庫(kù)建模的基本教程,LINQ to SQL被集成在.NET框架之中,需要的朋友可以參考下2016-03-03
C# 檢索不區(qū)分大小寫(xiě)并高亮顯示實(shí)例詳解
這篇文章主要介紹了C# 檢索不區(qū)分大小寫(xiě)并高亮顯示實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01

