1. 程式人生 > >WebApi 跨域問題解決方案:CORS

WebApi 跨域問題解決方案:CORS

前兩篇文章介紹了WebApi專案的建立測試,今天來說說WebApi跨域訪問的問題。本篇主要介紹了利用CORS解決跨域問題一些細節和具體步驟,下面來看看吧。

一、釋出WebApi

既然是解決WebApi跨域問題,那WebApi(http://localhost:9002)和網站(http://localhost:57447)當然是單獨部署了,只有這樣WebApi服務和網站的域名才會不同,要不怎麼出現垮域哇,主要程式碼如下:

[RoutePrefix("api/prefix")]
public class PleasureController : ApiController
{
    [Route("Pleasure/GetOne/{age:int=16}")]
    [HttpGet]
    public IEnumerable<string> GetOne(int age)
    {
        return new string[] { "GetOne(int age)->value1", "GetOne(int age)->value2" };
    }

    [HttpGet]
    public string GetOne(int id, string name, int age)
    {
        return string.Format("GetOne(int id, string name, int age)->id={0},name={1},age={2}", id, name, age);
    }

    [HttpGet]
    public string GetList()
    {
        return "GetList()->value";
    }
}

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API 路由
        config.MapHttpAttributeRoutes();

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

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

二、不做跨域處理進行請求

function invoke1() {
    $.ajax({
        type: "get",
        url: "http://localhost:9002/api/Pleasure/GetOne/5",
        contentType: "application/json",
        data: "name=aaa&age=12",
        dataType: "json",
        success: function (data) {
            $("#result").val(data);
        },
        error: function (data) {

        }
    });
}

三、CORS解決跨域問題的原理 

CORS全稱Cross-Origin Resource Sharing,中文全稱跨域資源共享,是一種允許當前域的資源被其他域的指令碼請求訪問的機制。它解決跨域問題的原理是通過向http的請求報文和響應報文裡面加入相應的標識告訴瀏覽器它能訪問哪些域名的請求。比如我們向響應報文裡面增加這個Access-Control-Allow-Origin:http://localhost:57447,就表示支援http://localhost:57447裡面的所有請求訪問系統資源。

四、CORS解決跨域問題的步驟 

1、WebApi專案設定

既然是設定資源能被哪些域名訪問,那當然是在WebApi專案中設定了,如果是在自己的網站裡設定可以訪問哪些服務,怎麼會有安全可言?

2、設定WebApiConfig.cs

三個*表示本服務支援任意請求來訪問,實際中除了完全開放的服務,其他專案肯定不能這麼幹。到此為止跨域問題就已經解決了。

public static void Register(HttpConfiguration config)
{
    //跨域配置
    config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

    // Web API 路由
    config.MapHttpAttributeRoutes();

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

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

3、在網站中再次訪問WebApi

此時再次出發按鈕的點選事件,就能正常獲取到結果了。

並不是所有的瀏覽器都支援CORS來解決跨域問題,如下圖所示IE8、IE9需要進行單獨處理,必須在呼叫處指定 jQuery.support.cors = true;。至於網上說的CORS對IE8、9的解決方案XDomainRequest是怎麼回事,本文不做探討。

jQuery.support.cors = true;
function invoke1() {
    $.ajax({
        type: "get",
        url: "http://localhost:9002/api/Pleasure/GetOne/5",
        contentType: "application/json",
        data: "name=aaa&age=12",
        dataType: "json",
        success: function (data) {
            $("#result").val(data);
        },
        error: function (data) {

        }
    });
}

4、設定跨域引數

第二步中使用的是config.EnableCors(new EnableCorsAttribute("*", "*", "*"));這樣是很不安全的,現在設定為只允許某域名能訪問

public static void Register(HttpConfiguration config)
{
    //跨域配置
    config.EnableCors(new EnableCorsAttribute("http://localhost:57447", "*", "*"));
    //config.EnableCors(new EnableCorsAttribute("http://localhost:57777,http://localhost:57447", "*", "*"));

    // Web API 路由
    config.MapHttpAttributeRoutes();

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

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

若允許多個域名訪問WebApi,可用逗號隔開,示例程式碼如下:

public static void Register(HttpConfiguration config)
{
    //跨域配置
    config.EnableCors(new EnableCorsAttribute("http://localhost:57777,http://localhost:57447", "*", "*"));

    ......
}

5、通過配置檔案設定跨域引數

如果在程式碼中把跨域引數寫死那每次想改配置就必須改程式碼,這很不方便,我們不如將跨域引數放到配置檔案中,這樣需要變動的時候只改配置檔案即可。


 

五、細粒度設定支援跨域 

如果只想讓某個方法支援跨域訪問的話,可以利用EnableCors特性來實現,EnableCors特性可以加到控制器、方法上,示例如下:

public class PleasureController : ApiController
{
    [Route("Pleasure/GetOne/{age:int=16}")]
    [HttpGet]
    public IEnumerable<string> GetOne(int age)
    {
        return new string[] { "GetOne(int age)->value1", "GetOne(int age)->value2" };
    }

    [EnableCors(origins: "http://localhost:57447", headers: "*", methods: "*")]
    [HttpGet]
    public string GetOne(int id, string name, int age)
    {
        return string.Format("GetOne(int id, string name, int age)->id={0},name={1},age={2}", id, name, age);
    }

    [HttpGet]
    public string GetList()
    {
        return "GetList()->value";
    }
}