ajax跨域訪問 JQuery的跨域詳解

關于跨域問題一直是我們比較糾結的地方,下面我來總結一下關于ajax跨域訪問及JQuery的跨域的原理與解決辦法,希望此方法對各位同學有所幫助。

JS的跨域問題,我想很多程序員的腦海裏面還認爲JS是不能跨域的,其實這是一個錯誤的觀點;

有很多人在網上找其解決方法,教其用IFRAME去解決的文章很多,真有那麽複雜嗎?

其實很簡單的,如果你用JQUERY,一個GETJSON方法就搞定了,而且是一行代碼搞定。

今天2013年8月2日又抽時間整理了下,修改了優化線上調用的方法。

我這裏提供了線上測試調用的功能,方便大家測試。點擊查看

其實跨域有兩種思路,思路一:就是通過js跨域訪問;思路二:是通過後台寫代碼訪問

下面說下兩種方法的實現:

思路一:通過js跨域訪問

一、伺服器端(遠程訪問段),構造指定的json格式:

代碼如下
var url = "http://www.111cn.net /CsAjax.do?method=getCrossJson&jsoncallback=?"
$.getJSON(url,
{www_url:"www.111cn.net"},
function(json) {
//返回格式: ?(json_data)
/*返回數據: ?([{"www_url":"www.111cn.net","www_name":"www_name",
"items":[{"p_name":"安徽省","p_index":340000},{"p_name":"北京市","p_index":110000}]}]) */
//調用實例:alert(json[0].www_url);
}); 


注意:CsAjax.do?method=getCrossJson中,在輸出JSON數據時,一定要帶參數:jsoncallback,並將獲取的內容放到返回JSON數據的前面,假設實際獲取的值爲Jquery123456_7890123,那麽返回的值就是 Jquery123456_7890123([{"www_url":"www.111cn.net","www_name":"www_name","items":[{"p_name":"安徽省","p_index":340000},{"p_name":"北京市","p_index":110000}]}]);

這個貼上我的遠程端的獲取代碼java寫的其他語言類似參考:

代碼如下
String www_url = (String) request.getAttribute("www_url");
String jsoncallback = (String) request.getAttribute("jsoncallback");
if (StringUtils.isBlank(www_url)) {
www_url = "www.111cn.net";
}
JSONObject jsonb = new JSONObject();

jsonb.put("www_url", www_url);
jsonb.put("www_name", "愛森家園");

JSONArray items = new JSONArray();
JSONObject item = new JSONObject();
item.put("p_name", "安徽省");
item.put("p_index", 340000);
items.put(item);
jsonb.put("p_name", "北京市");
jsonb.put("p_index", 110000);
items.put(item);
jsonb.put("items", items);

String json = jsoncallback + "([" + jsonb.toString() + "])";
if (StringUtils.isNotBlank(jsoncallback)) {
//將特殊構造的數據:json 返回到頁面
} else {
//將正常的數據jsonb返回到頁面
}

因爲getJSON跨域的原理是把?隨機變一個方法名,然後返回執行的,實現跨域回應的目的。

二、客戶端實際調用, 下面一個是跨域執行的真實例子(可跨所有域名):

代碼如下

<script src="/scripts/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$.getJSON("http://www.111cn.net /CsAjax.do?method=getCrossJson&jsoncallback=?",
{www_url:"www.111cn.net"},
function(json) {
alert(json[0].www_url);
alert(json[0].www_name);
alert(json[0].items[0].p_name);
});
</script>

後台寫代碼訪問


第一種思路有一個缺陷:就是如果需要訪問的服務端你無法控制的話,那麽你也就無計可施了,所以提供第二種思路,後台通過HttpClient 和 HttpGet 直接訪問,

然後在後台獲取訪問的數據,在做處理,返回到頁面即可。

這個可以參考我的文章:有道翻譯 使用


jQuery跨域原理


浏覽器會進行同源檢查,這導致了跨域問題,然而這個跨域檢查還有一個例外那就是HTML的<Script>標記;我們經常使用<Script>的src屬性,腳本靜態資源放在獨立域名下或者來自其它站點的時候這裏是一個url;這個url 回應的結果可以有很多種 , 比如 JSON, 返回的 Json 值成爲 <Script> 標簽的 src 屬性值 . 這種屬性值變化並不會引起頁面的影響 . 按照慣例,浏覽器在 URL 的查詢字符串中提供一個參數,這個參數將作爲結果的前綴一起返回到浏覽器 ;

看下面的例子:

代碼如下
<script type="text/javascript" src="http://domain2.com/getjson?jsonp=parseResponse"> </script>

回應值:parseResponse({"Name": "Cheeso", "Rank": 7})

這種方式被稱作 JsonP ;(如果鏈接已經失效請點擊這裏: JSONP ) ;即:JSON with padding 上面提到的前綴就是所謂的“padding”。 那麽 jQuery 裏面是怎麽實現的呢?

貌似並沒有 <Script> 標記的出現!? OKay ,


頁面調用的是getJSON:

代碼如下
getJSON: function ( url, data, callback ) {
return jQuery.get(url, data, callback, " json " );
},


繼續跟進

代碼如下
get: function ( url, data, callback, type ) {
// shift arguments if data argument was omited
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = null ;
}

return jQuery.ajax({
type: " GET " ,
url: url,
data: data,
success: callback,
dataType: type
});


跟進 jQuery.ajax,下面是 ajax 方法的代碼片段:

代碼如下
// Build temporary JSONP function
if ( s.dataType === " json " && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
jsonp = s.jsonpCallback || ( " jsonp " + jsc ++ );

// Replace the =? sequence both in the query string and the data
if ( s.data ) {
s.data = (s.data + "" ).replace(jsre, " = " + jsonp + " $1 " );
}

s.url = s.url.replace(jsre, " = " + jsonp + " $1 " );

// We need to make sure
// that a JSONP style response is executed properly
s.dataType = " script " ;

// Handle JSONP-style loading
window[ jsonp ] = window[ jsonp ] || function ( tmp ) {
data = tmp;
success();
complete();
// Garbage collect
window[ jsonp ] = undefined;

try {
delete window[ jsonp ];
} catch (e) {}

if ( head ) {
head.removeChild( script );
}
};
}

if ( s.dataType === " script " && s.cache === null ) {
s.cache = false ;
}

if ( s.cache === false && type === " GET " ) {
var ts = now();

// try replacing _= if it is there
var ret = s.url.replace(rts, " $1_= " + ts + " $2 " );

// if nothing was replaced, add timestamp to the end
s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? " & " : " ? " ) + " _= " + ts : "" );
}

// If data is available, append data to url for get requests
if ( s.data && type === " GET " ) {
s.url += (rquery.test(s.url) ? " & " : " ? " ) + s.data;
}

// Watch for a new set of requests
if ( s.global && ! jQuery.active ++ ) {
jQuery.event.trigger( " ajaxStart " );
}

// Matches an absolute URL, and saves the domain
var parts = rurl.exec( s.url ),
remote = parts && (parts[ 1 ] && parts[ 1 ] !== location.protocol || parts[ 2 ] !==location.host);

// If we're requesting a remote document
// and trying to load JSON or Script with a GET
if ( s.dataType === " script " && type === " GET " && remote ) {
var head = document.getElementsByTagName( " head " )[ 0 ] || document.documentElement;
var script = document.createElement( " script " );
script.src = s.url;
if ( s.scriptCharset ) {
script.charset = s.scriptCharset;
}

// Handle Script loading
if ( ! jsonp ) {
var done = false ;

// Attach handlers for all browsers
script.onload = script.onreadystatechange = function () {
if ( ! done && ( ! this .readyState ||
this .readyState === " loaded " || this .readyState === " complete " ) ) {
done = true ;
success();
complete();

// Handle memory leak in IE
script.onload = script.onreadystatechange = null ;
if ( head && script.parentNode ) {
head.removeChild( script );
}
}
};
}

// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
head.insertBefore( script, head.firstChild );

// We handle everything using the script element injection
return undefined;
}

上面的代碼第1行到第10行:判斷是JSON類型調用,爲本次調用創建臨時的JsonP方法,並且添加了一個隨機數字,這個數字源于用日期值;

這個地方也就是Taven.李錫遠所說的“隨機變一個方法名”;

關注第14行,這一行相當關鍵,注定了我們的結果最終是<Script> ;然後是構造Script片段,第95行在Head中添加該片段,修成正果;

不僅僅是jQuery,很多js框架都是用了同樣的跨域方案,:)說到這裏,嗯,這就是getJSON跨域的原理,趙本山說了“情況呢就是這麽個情況”

更多相關文章
  • 文章利用舉例說明了關于PHP5面向對象訪問控制 Public,private,protected詳細說明,有需要的朋友可以參考一下.在PHP5中增強了面向對象的機制,加入了面向對象常見的public.private.
  • 文章分享一篇關于利用了jquery的ajax 來訪問wcf 伺服器,同時支持GET.POST.PUT.DELETE等常用的訪問方法,後面一個實例介紹了跨域訪問WCF有需要了解的同學可以看看. 代碼如下 using jquery ajax call wcf service get/post/put/d
  • JSONP(JSON with Padding)是JSON的一種"使用模式",可用于解決主流浏覽器的跨域數據訪問的問題.現在我們來用JSONP解決Ajax跨域訪問問題.前幾天,工作上有一新需求,需要前端web頁面異步調用後台的Webservice方法返回信息.實現方法有多種,本例 ...
  • 一篇朋友很久前寫的asp.net中WebResponse 跨域訪問示例,下面我轉過來與大家一起學習學習,希望文章對大家會有幫助.前兩天,一個朋友讓我幫他寫這樣一個程序:在asp.net裏面訪問asp的頁面,把數據提交
  • 本文章總結多種關于Iframe跨域訪問不能寫cookie問題的解決辦法,其實我最喜歡的是利用程序來解決,前面的設置站點信任是不可取的哦.假設A嵌套了B解決方法:第一種很簡單:將系統B設置爲可信站點.第二種:IE設置隱
  • 現在浏覽器多但是很多時候標准不一樣兼容性也不好,下面我來介紹解決ff和IE9對icon font字體的跨域訪問不兼容問題,這裏介紹的是apache與nginx的方法.apache解決辦法可以將字體文件放到同域的伺服器上或修改伺服器配置.把如下代碼加到你的伺服器配置文件中去,我用的是apache2,這 ...
  • 提供一個簡單的jQuery AjaxQueue 實例詳解,主要講到了管理ajax請求的發送順序等,原理是如果前一個請求未返回,新的請求發出,那麽撤銷前一個請求,也就是新的請求"覆蓋"原請求,有需要的朋友可以參考一下.complete回調在jquery1.5以後可以是一個函數數組, ...
  • PHP+AJAX無刷新分頁實現代碼詳解,最近在看ajax 教程,就想寫個簡單入門的PHP+AJAX無刷新分頁,我們依據ajax開發框架 代碼如下 var http_request=false; function send_request(url){//初始化,指定處理函數,發送請求的函數http_r
一周排行