自己实现一个JsonP

在没有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);

}

使用实例:

当你页面需要使用jsonp跨域的时候,只需要这样调用即可:

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();

}

相关文章

文章浏览阅读2.4k次。最近要优化cesium里的热力图效果,浏览...
文章浏览阅读1.2w次,点赞3次,收藏19次。在 Python中读取 j...
文章浏览阅读1.4k次。首字母缩略词 API 代表应用程序编程接口...
文章浏览阅读802次,点赞10次,收藏10次。解决一个JSON反序列...
文章浏览阅读882次。Unity Json和Xml的序列化和反序列化_uni...