ASP.NET MVC中設置跨域
1、什么是跨域請求
js禁止向不是當前域名的網站發起一次ajax請求,即使成功respone了數據,但是你的js仍然會報錯。這是JS的同源策略限制,JS控制的並不是我們網站編程出現了問題。客戶端(網頁)和后台編程都可以有效解決這個問題。客戶端可以通過JSONP來完成跨域訪問;在ES6中為了解除同源策略問題,想出一個辦法:當被請求網站為響應頭respone添加了一個名為Access-Control-Allow-Origin的header,設置其值等於發起請求網站的域名地址的話,這次請求被視為允許。其中Access-Control-Allow-Origin的值為*時表示允許所有網站的跨域請求。
2、程序中添加Header頭允許客戶端跨域請求
這里有很多方法可以方法可以在返回數據時添加header頭。
請注意:同名Header可以有多個 ,但是運行時使用的是第一個,addHeader添加時,如果同名header已存在,則追加至原同名header后面(不起作用),setHeader,如果同名header已存在,則覆蓋一個同名header。
在action中添加代碼
HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Origin", "*");
在webconfig添加應用程序配置:
<system.webServer> <httpProtocol> <customHeaders> <!-- 先移除后添加,確保起作用 --> <remove name="Access-Control-Allow-Origin" /> <remove name="Access-Control-Allow-Headers" /> <remove name="Access-Control-Allow-Methods" /> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="Content-Type" /> <add name="Access-Control-Allow-Methods" value="*" /> </customHeaders> </httpProtocol> </system.webServer>
添加action過濾器
不論webapi還是mvc的action,我們都可以重寫ActionFilterAttribute過濾器的OnException方法來在action執行完成之后,為http響應添加header頭;OnException方法意為在action執行完成之后進行的操作。這個過濾器可以添加在action或者controller上,但是這樣就要為每一個action或者controller打上這個過濾器,這里將我們重寫的action過濾器添加在了全局的過濾器中,這樣,每一個action在執行完成之后都會觸發這個過濾器,這里以webapi為例。新建類:
/// <summary> /// 跨域 /// </summary> public class Cores:ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { base.OnActionExecuted(actionExecutedContext); actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin","*"); } }
代碼中注冊過濾器
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // 將 Web API 配置為僅使用不記名令牌身份驗證。 config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // Web API 路由 config.MapHttpAttributeRoutes(); config.Filters.Add(new Cores()); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
在Starpup.cs類中設置header頭
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Owin; using Owin; using System.Web; [assembly: OwinStartup(typeof(WebApiTest.Startup))] namespace WebApiTest { public partial class Startup { public void Configuration(IAppBuilder app) { // 不能使用這種方式添加必須使用app的相應方法或者中間件實現 // HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); //app.UseWebApi(); app.Use(async (context,next)=> { context.Response.Headers.Set("Access-Control-Allow-Origin", "*"); await next(); }); } } }
startup.cs類是應用啟動類,我本來以為直接在方法中直接把HttpContext.Current.Response.AddHeader添加一個頭就行了,但是發現不行,必須通過參數app才能成功設置響應頭,后來我才知道,這個startup.cs類遠不止看到的那么簡單!拿出來可以當作好比一本書的一個章節來講了!以后再深入了解這個類。
3、引入Script標簽獲取數據
一些JSONP之類的客戶端跨域請求就不說了,最近發現了構造Script標簽也可以作為獲取數據的方法,很開心。
即使服務端不設置允許跨域的header頭,js也可以變通獲取數據,不過仍然需要服務端的配合。
這個原理是;當通過script標簽的src地址引入某個資源的JS代碼的時候,就相當於src地址的JS代碼直接就在本地一樣。相應的,其他地址的js變量也會引入當前頁面
比如百度地圖的JsAPI
比如雅虎獲取IP地址的接口
接口:http://pv.sohu.com/cityjson
返回JS代碼:var returnCitySN = {"cip": "115.238.95.194", "cid": "330100", "cname": "浙江省杭州市"};
頁面引入
<script src="http://pv.sohu.com/cityjson"></script>
然后console.log(returnCitySN)可以直接使用。
這就提供了思路,
var script = document.createElement("script"), script.src = "http://pv.sohu.com/cityjson"; script.onload=()=>{ console.log(returnCitySN); }
但是缺點是,服務端必須返回的是JS代碼。