javascript跨域問題
阿新 • • 發佈:2019-01-07
來源:http://www.jb51.net/article/31153.htm
javascript跨域有兩種情況:
1、基於同一父域的子域之間,如:a.c.com和b.c.com
2、基於不同的父域之間,如:www.a.com和www.b.com
3、埠的不同,如:www.a.com:8080和www.a.com:8088
4、協議不同,如:http://www.a.com和https://www.a.com
對於情況3和4,需要通過後臺proxy來解決,具體方式如下:
a、在發起方的域下建立proxy程式
b、發起方的js呼叫本域下的proxy程式
c、proxy將請求傳送給接收方並獲取相應資料
d、proxy將獲得的資料返回給發起方的js 程式碼和ajax呼叫一致,其實這種方式就是通過ajax進行呼叫的
發起方程式碼如下:
a、在發起方頁面和接收方頁面設定document.domain,並將值設為父域的主域名(window.location.hostname)
b、在發起方頁面建立一個隱藏的iframe,iframe的源是接收方頁面
c、根據瀏覽器的不同,通過iframe.contentDocument || iframe.contentWindow.document來獲得接收方頁面的內容
d、通過獲得的接收方頁面的內容來與接收方進行互動
這種方法有個缺點,就是當一個域被攻擊時,另一個域會有安全漏洞出現。 發起方程式碼:
b、發起方建立一個定時器,定時檢查自己的location.hash並作相應的處理
c、接收方建立一個隱藏的iframe,iframe的源指向發起方所在域的一個代理頁面,並將接收方根據發起方傳入的資料而處理後的資料通過代理頁面的hash值來傳送
d、接收方建立一個定時器,定時檢查自己的location.hash並作相應的處理
e、代理頁面建立一個定時器,定時檢查自己的location.hash並同步更新發起方頁面的hash值 www.a.com/a.html#aaa,其中#aaa就是location.hash值 4、window.name: a、發起方頁面建立一個隱藏的iframe,並且源指向接收方頁面
b、接收方在自己頁面通過script將需要傳送的資料放入window.name裡
c、發起方在iframe的onload方法裡將iframe的源改為和自己在同一個域下的代理頁面(因為只能是同一個域下才能訪問window.name的值)
d、獲取window.name的值(雖然iframe的源改變了,但是window.name的值不會變)
window.name的值差不多可以有2MB大小 5、HTML5的postMessage
a、發起方頁面建立一個隱藏的iframe,並且源指向接收方頁面
b、發起方頁面通過iframe.contentWindow.opener = {a: function(params){...}, b: function(params){...} ...}來定義可被接收方呼叫的方法
c、接收方頁面通過window.opener.a/window.opener.b來呼叫發起方定義的方法
d、接收方頁面通過parent.opener = {c: function(params){...}, d: function(params){...} ...}來定義可被髮起方呼叫的方法
e、發起方頁面通過opener.c/opener.d來呼叫接收方定義的方法 其實原理就是重置opener物件 7、window.navigator 適用於IE6、7,貌似現在還能用,還沒被補丁掉
a、發起方頁面建立一個隱藏的iframe,並且源指向接收方頁面
b、發起方頁面通過window.navigator.a = function(params){...}; window.navigator.b = function(params){...}; 來定義被接 收方呼叫的方法
c、接收方頁面通過window.navigator.a(params); window.navigator.b(params);來呼叫發起方定義的方法
d、接收方頁面通過window.navigator.c = function(params){...}; window.navigator.d = function(params){...}; 來定義被髮起方呼叫的方法
e、發起方頁面通過window.navigator.c(params); window.navigator.d(params);來呼叫接收方定義的方法
1、基於同一父域的子域之間,如:a.c.com和b.c.com
2、基於不同的父域之間,如:www.a.com和www.b.com
3、埠的不同,如:www.a.com:8080和www.a.com:8088
4、協議不同,如:http://www.a.com和https://www.a.com
對於情況3和4,需要通過後臺proxy來解決,具體方式如下:
a、在發起方的域下建立proxy程式
b、發起方的js呼叫本域下的proxy程式
c、proxy將請求傳送給接收方並獲取相應資料
d、proxy將獲得的資料返回給發起方的js 程式碼和ajax呼叫一致,其實這種方式就是通過ajax進行呼叫的
發起方Proxy程式碼如下:<form id="form1" runat="server"> <div> <input type="text" id="txtSrc" value="http://www.gzsums.edu.cn/webclass/html/html_design.html" style="width: 378px" /> <input id="btnProxy" type="button" value="通過Proxy獲取資料" onclick="GetDataFromProxy();" /><br /> <br /> <br /> </div> <div id="divData"></div> </form> </body> <script language="javascript" type="text/javascript"> function GetDataFromProxy() { var src = document.getElementById('txtSrc').value; var request = null; if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else if (window.ActiveXObject) { request = new ActiveXObject("Microsoft.XMLHTTP"); } request.onreadystatechange = function() { var ready = request.readyState; var data = null; { if (ready == 4) { data = request.responseText; document.getElementById('divData').innerHTML = data; } else { document.getElementById('divData').text = "Loading"; } } } var url = "Proxy.ashx?src=" + escape(src); request.open("get",url,false); request.send(null); } </script>
而情況1和2除了通過後臺proxy這種方式外,還可以有7種辦法來解決: 1、document.domain+iframe(只能解決情況1):using System.Data; using System.Linq; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Xml.Linq; using System.IO; using System.Net; using System.Text; namespace WebApplication1 { /// <summary> /// Summary description for $codebehindclassname$ /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class Proxy : IHttpHandler { const int BUFFER_SIZE = 8 * 1024; public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; string src = context.Request["src"]; WebRequest wr = WebRequest.Create(src); WebResponse wres = wr.GetResponse(); Encoding resEncoding = System.Text.Encoding.GetEncoding("gb2312"); StreamReader sr = new StreamReader(wres.GetResponseStream(), resEncoding); string html = sr.ReadToEnd(); sr.Close(); wres.Close(); context.Response.Write("<br/><br/><br/><br/>"); context.Response.Write(html); } public bool IsReusable { get { return false; } } } }
a、在發起方頁面和接收方頁面設定document.domain,並將值設為父域的主域名(window.location.hostname)
b、在發起方頁面建立一個隱藏的iframe,iframe的源是接收方頁面
c、根據瀏覽器的不同,通過iframe.contentDocument || iframe.contentWindow.document來獲得接收方頁面的內容
d、通過獲得的接收方頁面的內容來與接收方進行互動
這種方法有個缺點,就是當一個域被攻擊時,另一個域會有安全漏洞出現。 發起方程式碼:
<body>
<div>
<input type="text" id="txtSrc" value="http://b.a.com/DomainTest2.htm" style="width: 378px" />
<input id="btnDomain" type="button" value="通過Domain獲取資料" onclick="GetDataFromDomain();" /><br />
<br />
<br />
</div>
<div id="divData"></div>
</body>
<script language="javascript" type="text/javascript">
document.domain = 'a.com';
var src = document.getElementById('txtSrc').value;
var ifr = document.createElement('iframe');
ifr.src = src;
ifr.style.display = 'none';
document.body.appendChild(ifr);
function GetDataFromDomain() {
var doc = ifr.contentDocument || ifr.contentWindow.document;
alert(doc.getElementById("data").value);
}
</script>
接收方程式碼:
<body>
<input type="hidden" id="data" value="Cross Domain" style="width: 378px" />
</body>
<script language="javascript" type="text/javascript">
document.domain = 'a.com';
</script>
2、 動態建立script(也就是jsonp)
a、在發起方頁面動態載入一個script,script的URL指向接收方的一個處理地址(後臺),該地址返回的javascript方法會被執行,另外URL中可以傳入一些引數,該方法只支援GET方式提交引數。
b、載入的script可以在呼叫跨域js方法後再做一些自己的處理
3、location.hash+iframe: a、發起方建立一個隱藏的iframe,iframe的源指向接收方的頁面,並通過接收方頁面的hash值來傳送資料b、發起方建立一個定時器,定時檢查自己的location.hash並作相應的處理
c、接收方建立一個隱藏的iframe,iframe的源指向發起方所在域的一個代理頁面,並將接收方根據發起方傳入的資料而處理後的資料通過代理頁面的hash值來傳送
d、接收方建立一個定時器,定時檢查自己的location.hash並作相應的處理
e、代理頁面建立一個定時器,定時檢查自己的location.hash並同步更新發起方頁面的hash值 www.a.com/a.html#aaa,其中#aaa就是location.hash值 4、window.name: a、發起方頁面建立一個隱藏的iframe,並且源指向接收方頁面
b、接收方在自己頁面通過script將需要傳送的資料放入window.name裡
c、發起方在iframe的onload方法裡將iframe的源改為和自己在同一個域下的代理頁面(因為只能是同一個域下才能訪問window.name的值)
d、獲取window.name的值(雖然iframe的源改變了,但是window.name的值不會變)
window.name的值差不多可以有2MB大小 5、HTML5的postMessage
a、receiverWindow.postMessage(msg, targetOrigin),receiverWindow就是對接收訊息的window的引用,可以是iframe的contentWindow/window.open的返回值/window.frames中的一個;msg就是要傳送的訊息,string型別;targetOrigin用於限制receiverWindow的URI,包括主域名和埠,使用“*”表示無限制,但是為了安全起見還是需要設定下,以防把訊息傳送給惡意的網站,如果targetOrigin的URI和receiverWindow的不符,則放棄傳送訊息。
b、接收方通過message事件來獲得訊息,並且通過event.origin的屬性來驗證傳送方並通過event.data來獲得傳送的訊息內容,event.source來獲得傳送方的window物件
a、發起方頁面建立一個隱藏的iframe,並且源指向接收方頁面
b、發起方頁面通過iframe.contentWindow.opener = {a: function(params){...}, b: function(params){...} ...}來定義可被接收方呼叫的方法
c、接收方頁面通過window.opener.a/window.opener.b來呼叫發起方定義的方法
d、接收方頁面通過parent.opener = {c: function(params){...}, d: function(params){...} ...}來定義可被髮起方呼叫的方法
e、發起方頁面通過opener.c/opener.d來呼叫接收方定義的方法 其實原理就是重置opener物件 7、window.navigator 適用於IE6、7,貌似現在還能用,還沒被補丁掉
a、發起方頁面建立一個隱藏的iframe,並且源指向接收方頁面
b、發起方頁面通過window.navigator.a = function(params){...}; window.navigator.b = function(params){...}; 來定義被接 收方呼叫的方法
c、接收方頁面通過window.navigator.a(params); window.navigator.b(params);來呼叫發起方定義的方法
d、接收方頁面通過window.navigator.c = function(params){...}; window.navigator.d = function(params){...}; 來定義被髮起方呼叫的方法
e、發起方頁面通過window.navigator.c(params); window.navigator.d(params);來呼叫接收方定義的方法