Script标签跨域简单易懂,对于没有Post要求的数据请求,还是使用Script标签+Jsonp比较靠谱
代码:
a.scriptGet = function (url, callback,onerror) {
var stag = document.createElement("script");
stag.type = "text/javascript";
stag.src = url + "&t=" + (new Date()).getTime();
stag.iSnoBack = true;
stag.onload = stag.onreadystatechange = function () {
stag.iSnoBack = false;
if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
document.body.removeChild(stag);
if (callback)
callback();
}
}
document.body.appendChild(stag);
setTimeout(function () {
if(stag.iSnoBack)
{
document.body.removeChild(stag);
if (onerror)
{
onerror();
}
else
alert("请求的跨域资源:"+url+"没有在10秒内返回,可能已经发生错误,请检查或刷新页面");
}
},10000);
};
Script跨域要求服务器端返回的 ContentType = text/javascript
内容文件形如:
calbackName({"success":true,"errorinfo":"all OK"});
相当于在HTML的script标签内直接调用某个函数。跨域的Cookie支持没有理论上的可能性,数据安全性都需要自己定协议才能支持。
对于需要提交数据,特别是需要跨域Post文件的系统,Get标签就有各种限制了,这时候需要使用Form进行跨域,代码:
a.DoCallBack = function (fc) {
try {
eval(fc);
}
catch (e) {
alert("跨域数据传递返回数据错误:" + e.message);
}
}
var seriNo = 1;//跨域操作流水号
a.CPBack = function (frameID, data) {
var backFrm = document.getElementById(frameID);
if (!backFrm)
return;
var t = getHiddenDivDirect.Target;
t.removeChild(backFrm);
if (!backFrm.CPCallBackk)
return;
backFrm.CPCallBackk(data);
}
a.FormPost = function (mainCMD, subCmd, content, callBackName) {
//2层Frame跨域,无File上传
//如果需要上传File,那么需要在HTML的From中完成
var frm = getHiddenDiv(frm);
if (frm == null)
{
alert("跨域等待数操作最大值");
return;
}
frm.CPCallBackk = callBackName;
var mainCC = {};
mainCC.CallBack = frm.id;
mainCC.CrossPageUrl = CPConfig.Local.CPFile;
mainCC.Command = mainCMD;
var mainCCStr = JSON.stringify(mainCC);
frm.contentWindow.document.open();
var wDoc = frm.contentWindow.document;
wDoc.write("<html><head><title></title></head>");
wDoc.write("<body><form id='autoForm' enctype='multipart/form-data' action='");
wDoc.write(CPConfig.Server.Using);
wDoc.write("' target='hiddenFrm' method='post'><textarea name=\"c\">");
wDoc.write(content);
wDoc.write("</textarea><textarea name=\"a\">");
wDoc.write(mainCCStr);
wDoc.write("</textarea><textarea name=\"b\">");
wDoc.write(subCmd);
wDoc.write("</textarea></form><iframe name=\"hiddenFrm\"/></body></html>");
wDoc.close();
var formT = wDoc.getElementById("autoForm");
formT.submit();
}
function getHiddenDiv() {
var noSeriIO = seriNo++;
var frm = document.createElement("iframe");
frm.id = "ghChainHiddenPost" + noSeriIO;
var t = document.createElement("div");
t.id = "gfChainHiddenContainer";
t.style.cssText = "display:none;position:absolute;width:0px;height:0px;";
if (document.body == null)
alert("不能在Head的JS中Post数据,请移动到HTML末尾处");
else
document.body.appendChild(t);
getHiddenDivDirect.Target = t;
getHiddenDiv = getHiddenDivDirect;
t.appendChild(iframe);
return iframe;
}
function getHiddenDivDirect() {
var t = getHiddenDivDirect.Target;
if (t.childNodes.length > 20) {//======================最大跨域提交等待数;========================
return null;
}
var noSeriIO = seriNo++;
var frm = document.createElement("iframe");
frm.id = "ghChainHiddenPost" + noSeriIO;
t.appendChild(iframe);
}
这里的函数是提交大的数据对象。 如果需要提交文件,那么需要手工编辑iframe的内容,然后显示出来。
甚至,这里可以去掉iframe,将form放在任意HTML文件中,放在邮件中也没有问题。
其本质就是一个跨域的form提交操作,可以JS自动生成,也可以嵌入在HTML页面中,显示给用户让编辑修改内容后再提交到服务器。
数据提交到服务器端后,需要几个条件,才能通JS通知到原来的域:
1:服务器端返回一个特定的HTML页面,通过HASH值传递数据对象
2:在原始域,需要有一个特殊的数据接收文件来接收数据,并完成回掉
服务器端返回的HTML内容:CPCPFather.html
<html><head><title>跨域中间页</title></head><body>本页是Form Post后返回数据页,应将form的target指向一个隐藏的iframe,不应显示出来。
<iframe src="CPCP.html#callback({\"success\":true,\"errorinfo\":\"all ok\"})"></iframe>
</body></html>
其中的callback({\"success\":true,\"errorinfo\":\"all ok\"})是重点,上述实例中没有对数据进行escap操作,实际应用中,必须进行escape否则会有意外发生.
iframe和原始域虽然可以互相访问,但因为在不同的window对象下,函数可能无法找到。实际代码中可以直接把函数关联到window.top对象上,然后直接回掉window.top上的函数。上述代码的a对象,就设置了:
window.top.CPJS = a;
在原始域中CPCP.html文件内容
<html><head><title>跨域回调页</title></head>
<body>
本页面应该隐藏在iframe中。无可显示内容
<script type="text/javascript">
try{
var hStr = window.location.hash;
if (hStr[0] == '#')
{
hStr = hStr.substr(1, hStr.length - 1);
}
hStr = unescape(hStr);
window.top.CPJS.DoCallBack(hStr);
}
catch (e) {
alert("跨域回掉错误:"+e.message+"\r\n数据内容:"+hStr);
}
</script></body></html>
该文件是静态文件,建议放在根目录下。
代码已经通过测试,iframe跨域的响应非常及时。
整个过程没有使用settime来进行数据检测,已使用的两个settime函数是为了错误检测,可以去掉。
数据返回域的Cookie操作没有测试,估计在CPCPFather.html文件中,对Cookie操作不会有问题,有兴趣的同学可以帮忙测试一下。
OK.Thansk.