一、什么是站點跨域
了解跨域之前, 先了解下什么同源策略?
百度百科:
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
同源:同一個協議, 同一個主機, 同一個端口 即同一個站點, 比如說IIS服務器, 一個站點只能綁定一個端口
那為什么需要同源策略的支持呢?
因為假設你已經登陸一個站點, 服務器已經將一些敏感信息返回到了客戶端, 如果此時你的站點代碼中有一段訪問其他站點的代碼, 這段代碼又是獲取用戶的銘感信息, 又比如說用戶在訪問銀行網站,並且沒有登出。然后他又去了任意的其他網站,
剛好這個網站有惡意的js代碼,在后台請求銀行網站的信息。因為用戶目前仍然是銀行站點的登陸狀態,那么惡意代碼就可以在銀行站點做任意事情。例如,獲取你的最近交易記錄,創建一個新的交易等等。那是相當不安全的.
所以同源策略是相當重要的.即如果訪問了一個站點, 那么用戶在訪問這個站點的所有內容必須是這個站點的內容, 不允許訪問其他站點的內容.
二、"同源政策"限制的功能
隨着互聯網的發展,"同源政策"越來越嚴格。目前,如果非同源,共有三種行為受到限制。
(1) Cookie、LocalStorage 和 IndexDB 無法讀取。
(2) DOM 無法獲得。
(3) AJAX 請求不能發送。
雖然這些限制是必要的,但是有時很不方便,合理的用途也受到影響。
三、為什么要規避同源策略
1、Cookie問題
假設我們有一個站點,由於業務的擴展,一個站點無法承受這么大的業務量,常規的做法是將業務拆分,拆分成不同的站點.但是理論上拆分出來的站點還是歸屬於原來的站點,因為邏輯上這些站點屬於一個應用程序,所以我們需要使用多級域名的技術,給主站點分配一個主域名,其他的站點分配該主域名的子域名,集體請參考IIS 站點部署多級域名.
但是由於"同源策略"的影響,其中的一個業務站點無法共享其它站點的Cookie,因為它們只是一級域名相同,二級域名並不相同,但是理論上它們時同一個應用程序,所以Cookie必須共享.
問題重現,在主站點的MVC控制器的Index方法寫入一個Cookie信息,代碼如下:
public ActionResult Index() { var cookie = new HttpCookie("userInfo", "xiaochao"); cookie.Expires = DateTime.Now.AddDays(1);//設置cookie一天后過期 Response.SetCookie(cookie); return View(); }
在主站點的Index頁面下讀取cookie,代碼如下:
<script> $(function () { //輸出在主站點設置的cookie $(function () { //輸出cookie var username = document.cookie.split(";")[0].split("=")[1]; if (username) { alert(username); } else { alert("cookie沒有寫入"); } }); });
注意在打開瀏覽器前,請先清空瀏覽器緩存,主站點瀏覽器輸出:

ok,Cookie正常輸出,接着打開業務站點1,js代碼和上面的一樣

ok,問題很明顯,主站點並沒有將cookie共享到業務站點,所以這個問題必須解決.
解決方案如下:
(1)、服務器端設置Cookie的Domain屬性
通過主站點服務器端(不一定在主站點,也可以是業務站點,親測有效,這里不做演示)設置Cookie的Domain屬性為一級域名,這樣所有的在一級域名下的二級域名站點都可以共享Cookie,代碼如下:
public ActionResult Index() { var cookie = new HttpCookie("userInfo", "xiaochao"); cookie.Expires = DateTime.Now.AddDays(1);//設置cookie一天后過期 cookie.Domain = "a.com";//設置Domain屬性,這樣這個域名下的所有的子域名,所有站點都共享Cookie Response.SetCookie(cookie); return View(); }
主站點輸出:

業務站點1輸出:

ok,說明在Cookie設置生效了,所有的站點共享了Cookie.
(2)、客戶端Js腳本設置
3、.Net 站點下跨域問題的重現
現在有兩個站點,一個MVC站點,一個WebApi站點

此時有個業務,MVC站點需要訪問Api站點下面的一個Json方法,拿到對應的業務數據
Api站點的方法如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace SiteApi.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Title = "Home Page"; return View(); } /// <summary> /// 給MVC站點調用的方法 /// </summary> /// <returns></returns> [HttpPost] public ActionResult GetData() { return Json("666"); } } }
MVC頁面的調用代碼如下:
<script src="~/Scripts/jquery-1.10.2.js"></script> <script> $(function () { $.post("http://localhost:50187/Home/GetData", function (data) { alert(data); }); }); </script>
運行站點效果如下:

數據沒有出來,打開控制台發現了這個Error。百度提示,瀏覽器出現跨域行為,需要添加Asscss-COntrol-Allow-Origin頭.
4、為什么要規避跨域
先說說為什么要規避跨域?
上面的例子可以說明,且假設有一個應用集群,我們建設了一個用戶中心,該用戶中心提供一些用戶驗證的功能,如登陸校驗、權限等功能.那必須的,這個用戶中心是以站點的形式存在,而應用集群中所有的應用必須能訪問該用戶中心站點,來校驗用戶的可用性,
但是用戶中心站點對於應用集群中所有的應用來說都屬於外部應用,所以違反了同源策略,但是這個功能必須要實現.所以這種情況下,必須采用技術手段來規避同源策略.
5、解決方案
(1)、跨域資源共享 CORS 技術
Ajax請求受限於同源策略,而這種技術能解決這種限制.但是需要服務器和瀏覽器的協作,IE瀏覽器不能低於IE10.
(1)、Jsonp技術
下面用Jsonp技術來解決這個問題.在了解這個技術之前,你需要知道雖然同源策略不允許跨域Ajax請求,代碼支持跨域的文件訪問,這些文件包括圖片、Js文件等.這里我們就可以用特定的Ajax請求去訪問一個Js文件(也可以是html文件),將這個文件下載下來,那么瀏覽器會執行這個文件,而這個文件就包含別的站點的訪問數據.具體實現方法如下:
