JS的跨域问题,我想很多程序员的脑海里面还认为JS是不能跨域的,其实这是一个错误的观点;
有很多人在网上找其解决方法,教其用IFRAME去解决的文章很多,真有那么复杂吗?
其实很简单的,如果你用JQUERY,一个GETJSON方法就搞定了,而且是一行代码搞定。
今天2013年8月2日又抽时间整理了下,修改了优化在线调用的方法。
其实跨域有两种思路,
思路一:就是通过js跨域访问;思路二:是通过后台写代码访问
下面说下两种方法的实现:
@H_404_16@=================思路一:通过js跨域访问@H_404_16@=====================
一、服务器端(远程访问段),构造指定的json格式:
JavaScript
var url = "http://www.aiisen.com/CsAjax.do?method=getCrossJson&jsoncallback=?"
$.getJSON(url,{www_url:"www.aiisen.com"},function(json) {
//返回格式: ?(json_data)
/*返回数据: ?([{"www_url":"www.aiisen.com","www_name":"www_name","items":[{"p_name":"安徽省","p_index":340000},{"p_name":"北京市","p_index":110000}]}]) */
//调用实例:alert(json[0].www_url);
});
1
2
3
4
5
6
7
8
9
var
url
=
"http://www.aiisen.com/CsAjax.do?method=getCrossJson&jsoncallback=?"
$
.
getJSON
(
url
,
{
www_url
:
"www.aiisen.com"
}
,
function
(
json
)
{
//返回格式: ?(json_data)
/*返回数据: ?([{"www_url":"www.aiisen.com",
"items":[{"p_name":"安徽省","p_index":110000}]}]) */
//调用实例:alert(json[0].www_url);
}
)
;
注意:CsAjax.do?method=getCrossJson中,在输出JSON数据时,一定要带参数:jsoncallback,并将获取的内容放到返回JSON数据的前面,假设实际获取的值为Jquery123456_7890123,那么返回的值就是 Jquery123456_7890123([{“www_url”:”www.aiisen.com”,”www_name”:”www_name”,”items”:[{“p_name”:”安徽省”,”p_index”:340000},{“p_name”:”北京市”,”p_index”:110000}]}]);
这个贴上我的远程端的获取代码java写的其他语言类似参考:
JavaScript
String www_url = (String) request.getAttribute("www_url");
String jsoncallback = (String) request.getAttribute("jsoncallback");
if (StringUtils.isBlank(www_url)) {
www_url = "www.aiisen.com";
}
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返回到页面
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
String
www_url
=
(
String
)
request
.
getAttribute
(
"www_url"
)
;
String
jsoncallback
=
(
String
)
request
.
getAttribute
(
"jsoncallback"
)
;
if
(
StringUtils
.
isBlank
(
www_url
)
)
{
www_url
=
"www.aiisen.com"
;
}
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跨域的原理是把?随机变一个方法名,然后返回执行的,实现跨域响应的目的。
具体getJSON的使用说明,请参考JQUERY手册。
二、客户端实际调用,下面一个是跨域执行的真实例子(可跨所有域名):
JavaScript
$.getJSON("http://www.aiisen.com/CsAjax.do?method=getCrossJson&jsoncallback=?",function(json) {
alert(json[0].www_url);
alert(json[0].www_name);
alert(json[0].items[0].p_name);
});
1
2
3
4
5
6
7
8
9
10
=
"http://www.aiisen.com/commons/scripts/jquery.js"
type
=
"text/javascript"
>
=
"text/javascript"
>
$
.
getJSON
(
"http://www.aiisen.com/CsAjax.do?method=getCrossJson&jsoncallback=?"
,
{
www_url
:
"www.aiisen.com"
}
,
function
(
json
)
{
alert
(
json
[
0
]
.
www_url
)
;
alert
(
json
[
0
]
.
www_name
)
;
alert
(
json
[
0
]
.
items
[
0
]
.
p_name
)
;
}
)
;
@H_404_16@=================思路二:后台写代码访问@H_404_16@=====================
第一种思路有一个缺陷:就是如果需要访问的服务端你无法控制的话,那么你也就无计可施了,所以提供第二种思路,后台通过HttpClient 和HttpGet直接访问,
然后在后台获取访问的数据,在做处理,返回到页面即可。
这个可以参考我的文章:有道翻译 使用
=========================jQuery跨域原理==========================
浏览器会进行同源检查,这导致了跨域问题,然而这个跨域检查还有一个例外那就是HTML的
看下面的例子:
JavaScript
响应值:parseResponse({"Name": "Cheeso","Rank": 7})
1
2
=
"text/javascript"
src
=
"http://domain2.com/getjson?jsonp=parseResponse"
>
响应值:
parseResponse
(
{
"Name"
:
"Cheeso"
,
"Rank"
:
7
}
)
这种方式被称作JsonP;(如果链接已经失效请点击这里:JSONP);即:JSON with padding 上面提到的前缀就是所谓的“padding”。那么jQuery里面是怎么实现的呢?
貌似并没有
页面调用的是getJSON:
JavaScript
getJSON: function ( url,data,callback ) {
return jQuery.get(url,callback," json " );
},
1
2
3
getJSON
:
function
(
url
,
data
,
callback
)
{
return
jQuery
.
get
(
url
,
callback
,
" json "
)
;
}
,
继续跟进
JavaScript
get: function ( url,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
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
get
:
function
(
url
,
type
)
{
// shift arguments if data argument was omited
if
(
jQuery
.
isFunction
(
data
)
)
{
type
=
type
||
callback
;
callback
=
data
;
data
=
null
;
}
@H_214_1404@
return
jQuery
.
ajax
(
{
type
:
" GET "
,
url
:
url
,
data
:
data
,
success
:
callback
,
dataType
:
type
}
)
;
跟进jQuery.ajax,下面是ajax方法的代码片段:
Java
// 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// 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 "
)
;
@H_404_2024@
// 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
)
{
@H_814_3016@
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
@H_905_3404@
script
.
onload
=
script
.
onreadystatechange
=
null
;
if
(
head
&&
script
.
parentNode
)
{
head
.
removeChild
(
script
)
;
}
}
}
;
@H_957_3502@
}
// 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行,这一行相当关键,注定了我们的结果最终是
不仅仅是jQuery,很多js框架都是用了同样的跨域方案,:)说到这里,嗯,这就是getJSON跨域的原理,赵本山说了“情况呢就是这么个情况”
转载注明: http://www.itjhwd.com/ajax-jquery-kuayu/