1. 程式人生 > >.Net 通過設定Access-Control-Allow-Origin來實現跨域訪問

.Net 通過設定Access-Control-Allow-Origin來實現跨域訪問

目錄

  • # 前言
  • # 為每個API介面單獨新增響應頭
    • 1、針對 ASP.NET MVC 專案的Controllers
    • 2、針對 ASP.NET Web API專案的Controllers
    • 3、針對ASP.NET Web Forms專案中的處理程式
  • # 封裝一個攔截器,便於應用到控制器及介面上
    • 1、針對 ASP.NET MVC 專案的Controllers
    • 2、針對 ASP.NET Web API專案
    • 3、針對 ASP.NET Web API 2 還可以使用庫:Microsoft.AspNet.WebApi.Cors
      • 3.1 使用nuget安裝Microsoft.AspNet.WebApi.Cors
      • 3.2 開啟App_Start/WebApiConfig.cs檔案,在WebApiConfig.Register方法中配置WebApi.Cors
      • 3.3 在Controller上新增[EnableCors]屬性
      • 3.3 在Controller中的action上新增[EnableCors]屬性
      • 3.4 如果想應用到所有的api controller上,在WebApiConfig.Register方法中進行如下配置
      • 3.5 設定origins、HTTP methods、request headers示例
      • 3.6 Pass credentials in cross-origin requests
      • 3.7 瀏覽器支援情況
  • # 低版本IE實現跨域
  • # 參考

# 前言

.Net 通過設定Access-Control-Allow-Origin來實現跨域訪問,具體哪裡可以設定Access-Control-Allow-Origin呢?

  1. web.config中可以設定;
  2. 在IIS伺服器站點的功能檢視中設定HTTP響應標頭;
  3. 通過nginx代理伺服器進行設定;
  4. 在每個api介面上新增響應頭;
  5. 寫一個攔截器,應用到所有控制器上,在攔截器裡控制來訪域名,動態設定Access-Control-Allow-Origin的值;

本文主要詳細說下第四種和第五種方式,第五種方式也是對第四種方式的一種封裝;

# 為每個API介面單獨新增響應頭

1、針對 ASP.NET MVC 專案的Controllers

public class Default1Controller : Controller
{
    public ActionResult Test()
    {
        ControllerContext.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        /*
            --Your code
        */
        return Json("hello");
    }
}

2、針對 ASP.NET Web API專案的Controllers

public class TestController : ApiController
{
    public HttpResponseMessage Get(int id)
    {
        var response = Request.CreateResponse(HttpStatusCode.OK, new {Name="lily",age=10});

        response.Headers.Add("Access-Control-Allow-Origin", "*");
        //response.Headers.Add("X-Pagination", "TestHeader");
        //response.Headers.Add("Access-Control-Expose-Headers", "X-Pagination");
        return response;
    }
}

3、針對ASP.NET Web Forms專案中的處理程式

public class TestHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.AddHeader("Access-Control-Allow-Origin", "http://example.com");
        context.Response.AddHeader("Access-Control-Allow-Headers", "*");
        context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
        context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
        
        //context.Response.AddHeader("TestHeaderToExpose", "test");
        //context.Response.AddHeader("Access-Control-Expose-Headers", "TestHeaderToExpose");

        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

# 封裝一個攔截器,便於應用到控制器及介面上

1、針對 ASP.NET MVC 專案的Controllers

建立一個attribute:

using System.Web.Mvc;

namespace AllowCross.App_Code
{
    public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");

            //actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
            //actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Headers", "*");
            //actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            //context.Response.AddHeader("TestHeader", "test");
            //actionExecutedContext.Response.Headers.Add("Access-Control-Expose-Headers", "TestHeader");
            base.OnActionExecuting(filterContext);
        }
    }
}

將該attribute新增到action上:

using AllowCross.App_Code;

namespace AllowCross.Controllers
{
    public class Default1Controller : Controller
    {
        [AllowCrossSiteJson]
        public ActionResult Test()
        {
            return Json("hello");
        }
    }
}

2、針對 ASP.NET Web API專案

建立一個attribute:

using System.Web.Http.Filters;

namespace WepApiTest.App_Code
{
    public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext.Response != null)
            {
                actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
                //actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
                //actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Headers", "*");
                //actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
                //context.Response.AddHeader("TestHeader", "test");
                //actionExecutedContext.Response.Headers.Add("Access-Control-Expose-Headers", "TestHeader");
            }

            base.OnActionExecuted(actionExecutedContext);
        }
    }
}

將該attribute新增到acion上:

using WepApiTest.App_Code;

namespace WepApiTest.Controllers
{
    public class DefaultController : ApiController
    {
        [AllowCrossSiteJson]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
}

也可以將該attribute新增到整個controller上:

using WepApiTest.App_Code;

namespace WepApiTest.Controllers
{
    [AllowCrossSiteJson]
    public class DefaultController : ApiController
    {
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
}

3、針對 ASP.NET Web API 2 還可以使用庫:Microsoft.AspNet.WebApi.Cors

3.1 使用nuget安裝Microsoft.AspNet.WebApi.Cors

使用命令:

Install-Package Microsoft.AspNet.WebApi.Cors

使用管理器:

3.2 開啟App_Start/WebApiConfig.cs檔案,在WebApiConfig.Register方法中配置WebApi.Cors

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        //配置WebApi.Cors
        config.EnableCors();

        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

3.3 在Controller上新增[EnableCors]屬性

using System.Web.Http;
using System.Web.Http.Cors;

namespace WepApiTest.Controllers
{
    [EnableCors(origins: "http://WepApiTest.com", headers: "*", methods: "*")]
    public class TestController : ApiController
    {
        // GET: api/Test
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
}

3.3 在Controller中的action上新增[EnableCors]屬性

using System.Web.Http;
using System.Web.Http.Cors;

namespace WepApiTest.Controllers
{
    public class TestController : ApiController
    {
        // GET: api/Test
        [EnableCors(origins: "http://WepApiTest.com", headers: "*", methods: "*")]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
}

3.4 如果想應用到所有的api controller上,在WebApiConfig.Register方法中進行如下配置

using System.Web.Http;
using System.Web.Http.Cors;

namespace WebApplication2
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //配置WebApi.Cors
            var cors = new EnableCorsAttribute("www.example.com", "*", "*");
            config.EnableCors(cors);

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

3.5 設定origins、HTTP methods、request headers示例

// Allow CORS for all origins. (Caution!)
[EnableCors(origins: "*", headers: "*", methods: "*")]
[EnableCors(origins: "http://www.justsoso.com,http://www.example.com", 
    headers: "*", methods: "*")]
[EnableCors(origins: "http://www.example.com", headers: "*", methods: "get,post")]
[EnableCors(origins: "http://example.com", 
    headers: "accept,content-type,origin,x-my-header", methods: "*")]

3.6 Pass credentials in cross-origin requests

Credentials require special handling in a CORS request. By default, the browser does not send any credentials with a cross-origin request. Credentials include cookies as well as HTTP authentication schemes. To send credentials with a cross-origin request, the client must set XMLHttpRequest.withCredentials to true.

Using XMLHttpRequest directly:

var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/test');
xhr.withCredentials = true;

In jQuery:

$.ajax({
    type: 'get',
    url: 'http://www.example.com/api/test',
    xhrFields: {
        withCredentials: true
    }

In addition, the server must allow the credentials. To allow cross-origin credentials in Web API, set the SupportsCredentials property to true on the [EnableCors] attribute:

[EnableCors(origins: "http://myclient.azurewebsites.net", headers: "*", 
    methods: "*", SupportsCredentials = true)]

If this property is true, the HTTP response will include an Access-Control-Allow-Credentials header. This header tells the browser that the server allows credentials for a cross-origin request.

If the browser sends credentials, but the response does not include a valid Access-Control-Allow-Credentials header, the browser will not expose the response to the application, and the AJAX request fails.

Be careful about setting SupportsCredentials to true, because it means a website at another domain can send a logged-in user's credentials to your Web API on the user's behalf, without the user being aware. The CORS spec also states that ==setting origins to "*" is invalid if SupportsCredentials is true==.

3.7 瀏覽器支援情況

庫Web API CORS是服務端的處理方法,還必須要求客戶端支援CORS,支援情況請檢視該地址:
https://caniuse.com/#feat=cors

# 低版本IE實現跨域

參考:Cross-Domain AJAX for IE8 and IE9

# 參考

Setting Access-Control-Allow-Origin in ASP.Net MVC - simplest possible method
Microsoft.AspNet.WebApi.Cors
跨域資源共享 CORS 詳解

————————————————————————————————————————————