js下跨域的问题很让人头疼,本文讨论如何在javascript下实现跨域访问,以及如何利用jquery来实现跨域访问。
1,javascript下的跨域访问
1)实现基本原理
在html的DOM节点中,<script>节点是可以访问跨域服务器上的数据的,因此可以通过指定<script>的src属性值为跨域的服务器的url,从而实现跨域访问。
但是这个url的返回值不能是单纯的诸如{id:1, name: 'shyman', age: 18, male:true}格式的json对象
设想一下,假如有一个名为example.js的javascript文件,该javascript里面的内容是{id:1, name: 'shyman', age: 18, male:true},
当我们通过<script type="text/javascript" src="example.js"></script>去引用这个javascript的时候,可以说这个被引用的js没有任何一点作用,或者说我们根本访问不到js里面的内容。
怎么办??
于是,于是。。 如果上面的example.js里面的内容是var json = {id:1, name: 'shyman', age: 18, male:true}; callback(json);
或者是callback({id:1, name: 'shyman', age: 18, male:true});这样的js才有意义嘛,这才是一个正常的js嘛。。
注意上面这种数据格式,它在json的外面添加了一个函数callback,我们称这种数据格式为jsonp、或者json-p,翻译起来就是"填充了的json"(json with padding) ,这种叫法我们暂时可以不管。
现在我们正常的引用了example.js,有一个问题,js中的callback这个方法我们并没有定义,如果只引用这个js的话,浏览器肯定会提示脚本错误。
为了让浏览器不报脚本错误,同时也为了执行这个callback方法,在引入example.js脚本之前,我们要在另一个js中对callback方法进行定义,比如
function callback(data)
{
var ret = "";
for (
var pro
in data)
ret += pro + ":" + data[pro] + "\n";
alert(ret);
}
这个时候在页面刚打开的时候,会弹出从服务器上取回的jsonp数据中的json数据信息。
这样一个简单的js跨域就实现了。。
对了,对了。。还有刚开始提到的"<script>的src属性值为跨域的服务器的url",这个跨域的url返回值如何构造呢,以servlet服务为例。
在servlet的get和post方法中如下方式构造返回字符串就可以了
response.getWriter().write("callback({id: 1, name: 'shyman', age: 18, male:true});");
2)改进实现
如上1)所述,其实已经实现了基本的js跨域,在实际应用中,不可能像1)那样页面一加载完,就立即去跨域的服务器取jsonp数据,而是需要调用的时候去取。
其实很简单,首先定义callback方法(当然也可以是其他名字的方法,如xxx方法),然后动态地创建一个<script>元素,指定其url(该url返回值必须是由callback或xxx填充json的jsonp格式数据),并且动态地加入到<head>节点下。ok,就这么简单
<
html
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html;charset=gb2312"
>
<
title
>javascript crossdomain
</
title
>
<
script
type
="text/javascript"
>
var
script
=
document.createElement(
"
script
"
);
script.type
=
"
text/javascript
"
;
var
uid;
var
url
=
"
http://localhost:8080/xtgeomaps_app/CrossDomain
"
;
var
jsonpCallback
=
"
xxx
"
;
function
query()
{
uid
=
document.getElementById("us
erid
"
).value;
doQuery(uid, url, jsonpCallback);
}
function
doQuery(_uid, _url, _jsonpCallback)
{
script.src
=
_url
+
"
?_uid=
"
+
_uid
+
"
&_jsonpCallback=
"
+
_jsonpCallback;
//
返回字符串xxx({id:1, name: 'shyman', age: 18, male:true});
var
head
=
document.head
||
document.getElementsByTagName(
"
head
"
)[
0
]
||
document.documentElement;
if
( head
&&
script.parentNode ) {
head.removeChild( script );
}
head.insertBefore( script, head.firstChild );
}
function
xxx(data)
{
var
ret
=
""
;
for
(
var
pro
in
data)
ret
+=
pro
+
"
:
"
+
data[pro]
+
"
\n
"
;
alert(ret);
}
</
script
>
</
head
>
<
body
>
输入要查询的id:
<
input
id
="userid"
/><
br
/><
br
/>
<
input
type
="button"
value
="javascript跨域访问"
onclick
="query(uid, url, jsonpCallback)"
/>
</
body
>
</
html
>
跨域服务器servlet的代码为
protected
void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String uid = request.getParameter("_uid");
String jsonpCallback = request.getParameter("_jsonpCallback");
response.getWriter().write(jsonpCallback + "({id:" + uid + ", name: 'shyman', age: 18, male:true});");
//
构造javascript的执行函数字符串
}
js的跨域就搞定了
2,jquery跨域实现
其实上面js跨域的实现借鉴了jquery的实现方法,实现方法如下
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html;charset=gb2312"
>
<
title
>jquery crossdomain
</
title
>
<
script
type
="text/javascript"
src
="jquery-1.7.2.min.js"
></
script
>
<
script
type
="text/javascript"
>
function
query()
{
var
uid
=
$("#userid").val();
$.ajax({
url:
'
http://localhost:8080/xtgeomaps_app/CrossDomain
'
,
data: {_uid: uid},
dataType:
'
jsonp
'
,
jsonp:
"
_jsonpCallback
"
,
//
jsonpCallback: "xxx",
success:
function
(json) {
//
json={id:1, name: 'shyman', age: 18, male:true}
var
ret
=
""
;
for
(
var
pro
in
json)
ret
+=
pro
+
"
:
"
+
json[pro]
+
"
\n
"
;
alert(ret);
},
error:
function
(jqXHR, textStatus, errorThrown){
alert(textStatus);
}
});
}
</
script
>
</
head
>
<
body
>
输入要查询的id:
<
input
id
="userid"
/><
br
/><
br
/>
<
input
type
="button"
value
="jquery跨域访问"
onclick
="query()"
/>
</
body
>
</
html
>
跨域服务器端代码同1中的代码
总结一下吧,所谓js跨域,并不是所有的域都能跨,如果跨域服务器返回的不是jsonp数据格式,基本很难通过js跨域。
js跨域实现不了,怎么办?呵呵,那就只能通过自己写代理的方式了