1. 程式人生 > >ASP.NET跨域請求中的問題【CORS】

ASP.NET跨域請求中的問題【CORS】

瀏覽器的安全策略會阻止網頁向另一個站點發送ajax請求,同時也會阻止惡意站點從另一個站點讀取資料。這種限制被稱作“同源策略”。然而有時我們需要從一個站點訪問另一個站點,比如從一個站點訪問你的WebApi介面。
跨域資源共享-Cross Origin Resource Sharing(CORS)是一項W3C標準,允許服務端釋放同源策略,使得服務端在接受一些跨域請求的同時拒絕其他的跨域請求。相比較早期的JSONP等技術而言,CORS更加安全更加靈活。

1.什麼是“跨域”?

如果兩個URL的協議、域名、埠相同,那麼這兩個URL就是同源。不是同源的就是跨域的,也就是說凡是傳送請求URL的協議、域名、埠三者中任意一個與當前頁面的URL不同即為跨域。

下面的URL和上面兩個都不是同源的,也即是跨域的

注意:IE在比較是否同源時不考慮埠號

2.CORS如何工作

CORS特性提供了多個Http請求頭以供跨域請求使用。如果一個瀏覽器支援CORS,它會自動的為跨域請求加上相應的http請求頭,並不需要在javaScript中新增額外程式碼。

下面是一個跨域請求的示例,在Http請求頭的“Origin”項中是發起請求的站點域名。

GET http://myservice.net/api/test HTTP/1.1
Referer: http://myclient.net/
Accept: * / *
Accept-Language: en-US
Origin:

http://myclient.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.net

如果服務端允許了這個跨域請求,它會在http的Response的頭部設定項Access-Control-Allow-Origin。只有當Response中Access-Control-Allow-Origin的值與Request中Origin的值相匹配時,這個請求才會成功。如果Access-Control-Allow-Origin的值是”*”,則意味著任意跨域訪問都是被允許的。

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: http://myclient.net
Date: Wed, 05 Jun 2013 06:27:30 GMT
Content-Length: 17

如果在HttpResponse的頭部中沒有包含Access-Control-Allow-Origin項,跨域請求會失敗。即使服務端已經返回了正確的反饋,瀏覽器也不會將這個返回傳遞給客戶端應用。

No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://myclient.net’ is therefore not allowed access. The response had HTTP status code 500.

對於一些CORS請求,瀏覽器會在傳送實際需要的請求之前傳送一個額外的請求,我們稱之為“前置請求”。前置請求使用了Http Options方法,它包含了兩個特殊的請求頭Access-Control-Request-Method和Access-Control-Request-Headers。

OPTIONS http://myservice.net/api/test HTTP/1.1
Accept: * / *
Origin: http://myclient.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: accept, x-my-custom-header
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.net
Content-Length: 0

也就是說瀏覽器傳送了兩次請求,首先發送前置請求,驗證當前傳送請求的站點是否在允許訪問的域的範圍內,若驗證通過就傳送真正的請求獲取資料,否則請求就會被拒絕。在瀏覽器的除錯介面(F12-Network)我們也可以看到請求是有兩次。

在下列情況下,瀏覽器會跳過前置請求:
1.Http請求方法是GET、HEAD或POST
2.Http請求的Content-Type是application/x-www-form-urlencoded、multipart/form-data、text/plain
3.Http請求頭包含了Accept, Accept-Language, Content-Language, Content-Type

3.如何使用CORS

在ASP.NET應用中,可以使用NuGet獲取多個關於CORS的類庫:
這裡寫圖片描述
這些類庫分別位於Owin和AspNet名稱空間下,是CORS標準的不同實現,最終實現的效果是一樣的,只是使用環境和方式不太一樣。

3.1為WebApi新增CORS

通過NuGet安裝Microsoft.AspNet.WebApi.Cors為WebApi新增CORS。使用[EnableCros]屬性可以全域性設定CORS,也可以為Controller或Action單獨設定CORS。

全域性(Global)設定

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.EnableCors();
    }
} 

Controller設定

[EnableCors]
public class ValuesController : ApiController
{
    public HttpResponseMessage Post() { ... }
    [DisableCors]
    public HttpResponseMessage PutItem(int id) { ... }
}

Action設定

public class ValuesController : ApiController
{
    public HttpResponseMessage Post() { ... }

    [EnableCors]

    public HttpResponseMessage PutItem(int id) { ... }
}

其中[EnableCros]屬性有多個項可以設定,可以實現指定的站點才允許跨域訪問:[EnableCros(origin:”“,headers:”“,methods:”*”)]

3.2通過Owin實現CORS

Owin是微軟推廣的.NET Web應用程式與Web伺服器之間的介面,通過Owin實現CORS需要使用NuGet安裝Microsoft.Owin.Cros。在專案中新增Owin的Startup類:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        //允許跨域訪問  
        app.UseCors(CorsOptions.AllowAll);
    }
}

或者在web.config的system.webServer項下新增:

    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*"/>
        <add name="Access-Control-Allow-Headers" value="*"/>
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE"/>
      </customHeaders>
    </httpProtocol>

對於WebApi或MVC,如果已經引用並實現了Owin中的CROS,就不需要在WebApiConfig中設定config.EnableCros()了。

3.3.其他實現CORS的方式

除了在程式碼和配置檔案中新增CORS外,還可以在網站釋出後通過修改IIS配置來實現CORS
開啟IIS管理器,找到你的站點中的“HTTP響應標頭”:
這裡寫圖片描述

新增HTTP響應標頭:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:origin,x-requested-with,content-type
Access-Control-Allow-Methods:POST,GET,OPTIONS
Access-Control-Allow-Origin:*

注意:如果應用程式包含上述兩種以上情況時,只需在一處設定CORS,否則訪問應用時會出錯(Access-Control-Allow-Origin的值只能有一個):

Response to preflight request doesn’t pass access control check:The ‘Access-Control-Allow-Origin’ header contains multiple values ‘http://myclient.net,*’,but only one is allowed. Origin ‘http://myclient.net’ is therefore not allowed access.

參考文章