一、跨域?
1、什么是跨域?
跨域,指的是從一個域下訪問另一個域的資源。
注:只要協(xié)議、域名、端口有任何一個不同,都被當作是不同的域,之間的請求就是跨域操作。
2、跨域的原因?
瀏覽器的同源策略會導致跨域,這里同源策略又分為以下兩種;
- DOM同源策略:禁止對不同源頁面DOM進行操作。這里主要場景是iframe跨域的情況,不同域名的iframe是限制互相訪問的;
- XmlHttpRequest同源策略:禁止使用XHR對象向不同源的服務器地址發(fā)起HTTP請求;
3、為什么需要限制跨域?
安全,安全,安全。
cookie安全;
假如你登錄了銀行網(wǎng)站后,又訪問了某惡意網(wǎng)站,它便可以拿到你銀行登錄的一系列cookie,然后對銀行發(fā)起各種惡意操作,細思極恐;DOM安全;
假如有個惡意網(wǎng)站嵌套了一個指向某銀行網(wǎng)站的iframe,并且與窗口等寬高,那么你在iframe里面的所有操作節(jié)點,外層惡意網(wǎng)站都能夠獲取到,從而發(fā)起攻擊;資源安全。
假如你項目的AJAX接口,項目資源全都暴露在外,那么一個普通的本地HTML頁面都可以隨意請求你的項目資源,這樣當然是極度不安全的;
注:<script>、<img>、<iframe>等標簽則不受跨域限制。
二、解決方案
1、JSONP
JSONP(JSON with Padding),是JSON的一種使用模式。服務端返回的不是JSON,而是一段任意可執(zhí)行的JavaScript代碼。是利用script標簽的src屬性,將返回的內容采用JavaScript直譯器執(zhí)行,從而解決跨域請求資源的問題。
假設接口http://api.cjt.com/users返回[{"name": "曹建濤", "age": 18}],直接跨域訪問當然是不行的那么,我們修改server端,返回的格式為:
callback(
[{
name: "曹建濤",
age: 18
}]
)
然后在client端編寫callback方法,并添加script標簽,src指向http://api.cjt.com/users,即可解決;
實際開發(fā)中接口請求回調的處理方法都是獨立的,因而是請求后在當前頁面動態(tài)地添加script節(jié)點和回調方法,請求處理完成再行銷毀掉保證一致性。
var url = "http://api.cjt.com/users?callback=handle";
var obj = $('<script><\/script>');
obj.attr("src",url);
// 添加handle的具體實現(xiàn)
$("body").append(obj);
偉大的jQuery已經(jīng)為我們進行了完美的封裝,具體使用請查閱jQuery ajax。
由于實現(xiàn)原理的限制,JSONP只支持GET請求。
2、CORS
CORS(Cross-Origin Resource Sharing),直譯便是跨域資源共享,也是W3C正式推薦的標準。
跨域請求會出現(xiàn)著名的error提示:No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxx' is therefore not allowed access.也就是說服務端response header沒有對應的Access-Controll-Allow-Origin,因而xxx被拒絕訪問。
修改server端,添加對應的響應頭部:
response.setHeader("Access-Control-Allow-Origin", "*");
*代表允許所有來源,也可指定域名或IP。類似還有Access-Control-Allow-Methods、Access-Control-Allow-Headers,具體作用一看便知。然后便可直接正常使用ajax請求,無異。
注意復雜請求的preflight預檢請求,預檢請求必須通過才能發(fā)起后續(xù)真正的接口請求。
3、服務器代理
跨域限制是對于瀏覽器而言的,服務器不存在任何跨域問題。換句話說,可以手動實現(xiàn)一個server端用作代理,后臺獲取到所需域的資源,然后再返回給客戶端。
例如Java中的servlet,采用HttpURLConnection獲取到它域的資源,然后返回給client調用方即可。