在没有XMLHttpRequest lEvel2的时候,我们在使用Ajax的时候要实现客户端跨域就只能用jsonp。而jsonp的原理很简单,那就是利用了浏览器加载JavaScript和css等资源的时候是允许跨域加载的。
这也是以前黑客经常攻击我cms搭建网站的方式。莫名其妙让我的主页打开以后就跳到其他地方了。有的黑客直接给我写到首页代码里,有的黑客使用script脚本引入的方式。
jsonp的原理:
说出来很简单,那就是动态创建<script src="你ajax发起GET请求的地址"></script>这个DOM。
这样的话,浏览器就允许script标签请求跨域的内容,但是如何拿到服务端返回的内容并让浏览器端开发人员做点事情呢。
这里用到另一个技巧,很土的办法:那就是让服务端返回的内容就直接是一个函数调用的语法。
比如:服务端返回这样的内容-----> YourFunc({服务端要返回给客户的对象}){}
Demo:YourFunc({"a":1,"b":2})
然后客户端需要提前动态在全局空间内注册一个函数,其名称为YourFunc(data){}. 这样当<script src="ajaxurl"></script>请求返回数据后,浏览器解析其中的内容,会自动执行YourFunc({a:1,b:2}), 这样就调用了你提前注册好的函数YourFunc(data){};
你在全局空间中注册的函数可以这样写:YourFunc(rel){ 执行服务器结果处理的事情 }
我的JsonP封装:
我对Ajax请求的创建和执行进行了函数封装,以方便开发人员使用。ajax请求函数如下:
需要注意的是:在我的ajax函数使用时需要遵循一个约定,那就是服务端返回的数据约定为:
{
"success":true or false,
"errormsg":your logic error,
"data":your data when success,if Failed put it null is ok.
}
//函数形参说明:
//Ajax请求实现跨域(jsonP因为其实现机制原因故只能是GET请求)
//url-----,字符串,用户要ajax请求的URL
//callbackName,字符串,设置一个回调函数名。您只需要保证服务器端使用同名函数来包装json对象即可。一般服务器端可以类似于这样设置: response.write($Request['callback']+"({json对象})"),可保证与客户端设置一致。
//onsuccessfun,函数对象,表示请求成功后要执行的回调。(200状态码,且json状态为success)
//onlogicError,函数对象,表示请求的逻辑失败后的回调。(也是200状态码,但json状态为fail)
function ajaxjsonp(url,callbackName,onsuccessfun,onlogicError) {
//提前创建好回调函数
window[callbackName] = function (rel) {
if (rel.success == true) {
onsuccessfun(rel.data);//调用请求成功的处理函数
} else {
onlogicError(rel.errormsg);//调用逻辑错误处理的函数
}
};
//构造一个DOM向服务器发请求
var scriptdom = document.createElement("script");
var callbackRequest = "callback="+callbackName;
url = url.indexOf("?")>0?url + "&" + callbackRequest:url+"?"+callbackRequest;
scriptdom.src = url;//利用DOM向服务器发起GET请求
document.body.appendChild(scriptdom);
}
使用实例:
CYJLIB.ajaxjsonp("http://localhost:54675/","cyjddcallback",function (data) { document.getElementById("ttt").innerHTML = data.a },function (msg) { document.getElementById("ttt").innerHTML = msg;});
以上语句中CYJLIB请忽略即可,我只是把ajaxjsonp函数放入了一个对象而已。 后面的传参中上文都有介绍,很容易理解。关于callbackName这个参数,只要你服务器像上文那样设置好了,那客户端就可以随意填写。
缺点:
我写的这个函数无法检测HTTP请求中的错误,也无法获取到请求过程中的状态---比如“正在请求”。
另外,jsonp对服务器来说是有安全危险的,比如任何人都可以用浏览器去调用你的接口,给你带来了流量损耗。
同时,浏览器这种机制(bug)也会让恶意的人利用,当他取得你页面相关权限后,来跨域注入恶意js代码到你的页面。
所幸,html5提供的XHR level2解决了这种安全问题。
另送上非跨域请求的ajax包装函数:
//Ajax请求封装函数
//GorP,string类型,表示这个ajax请求使用Get还是Post方式
//欧尼
function ajax(GorP,url,onprocessfun,onhttpError,onlogicError) {
//创建考虑兼容性的XMLHttpRequest对象
var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
//打开http连接准备向服务器指定的URL发送post请求(Get请求可能会有缓存问题,所以尽量用post请求)
xmlhttp.open(GorP,true);
//定义好xmlhttp对象接收到返回状态值时的事件。
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
clearTimeout(timer);
//返回状态码4代表服务端已经完成了返回数据的任务。
//接下来判断http报文里的状态码
if (xmlhttp.status == 200) {
var rel = JSON.parse(xmlhttp.responseText);
if (rel.success = true) {
onsuccessfun(rel.data);//调用请求成功的处理函数
} else {
onlogicError(rel.errormsg);//调用逻辑错误处理的函数
}
}
}
}
//超时处理:放弃xhp请求,并调用onerror函数,把错误码给onerror。
timer = setTimeout(function () { if (xmlhttp) { xmlhttp.abort(); } onhttpError(xmlhttp.statusText); },20000);
//上面定义好了xmlhttprequest对象,而且设置了该对象状态变化时的事件。接下来开始发送请求
xmlhttp.send();
onprocessfun();
}