目前的浏览器没有赋予Javascript脚本更大的权力来操作本地api,比如,文件,socket,等。
Javascript能够操作的东西目前仅限于浏览器创建出来的资源,比如,dom树,socke连接。
如果一个文件是Javascript(v8的js解释器引擎DLL)发起的读写操作,浏览器会拒绝。
如果一个socket是js引擎发起的,浏览器也会拒绝。
Javascript引擎可以利用(1)已经打开的连接, (2)打开指向本网站域的URL
ajax跨域请求限制实际上是js的脚本安全限制:
**** 指向其他网站的url连接必须是显示的有浏览器打开,不能有动态脚本发起。
**** 指向本站的url连接可以有动态脚本直接请求。
解决方案:
网上流行的4中解决方式,总结了一下,web前端主要可以考虑以下2种方式。
参考:http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html
服务器A上有个页面App.htm的js脚本需要在客户端跨域访问服务器B上的页面data.htm
在服务器A上再创建一个空白的proxy.htm,用于修改iframe的src属性,进而改变域。
测试环境配置:
服务器A,B的ip为10.12.32.17,在客户端机器上设置域名解析,修改hosts文件
10.12.32.17 www.a.com 10.12.32.17 www.b.com 10.12.32.17 www.c.com 10.12.32.17 www.d.com
客户端也可以是10.12.32.17,域名解析改成127.0.0.1就好了。
先看app.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <META http-equiv="Content-Type" content="text/html; charset=utf-8"> <HTML><HEAD></HEAD><BODY>app.htm
<script> var ifr = document.createElement('iframe'); ifr.src = 'http://www.b.com/data.htm'; var load_domain_A = 0; /** * 这个加载完毕函数为被回调2次 * 一次是data.html加载完毕的时候 * 一次是proxy.htm加载完毕的时候 */ ifr.onload = function (){ if ( load_domain_A == 0){// 说明是data.htm加载完毕 load_domain_A = 1; // 修改标记 // 修改iframe的属性,让浏览器"误"认为iframe的domain已经切换了 // 浏览器会"误"认为这个时候,跨域访问是安全的。 ifr.contentWindow.location = 'http://www.a.com/proxy.htm'; return ; }else{ // 这个时候是proxy.htm加载完毕了 alert("[window.name]=" + ifr.contentWindow.name); // 销毁资源 ifr.contentWindow.document.write(''); ifr.contentWindow.close(); document.body.removeChild(ifr); } } document.body.appendChild(ifr); </script>
</BODY> </HTML>
再看data.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <META http-equiv="Content-Type" content="text/html; charset=utf-8"> <HTML><HEAD></HEAD><BODY>data.htm <script> window.name = "[data from http://www.b.com/data.htm]"; </script> </BODY> </HTML>
首先明确一下,动态标签,不只是jsonp才用,
1) 查询模式: 也可以创建一个动态标签,直接请求一个静态的js,这个js干什么,我们就不关心了,ie,加载一些库,带来一些配置数据,但是我们需要查询或者等待这个script标签加载执行完毕,才可以访问相应的库,或者操作相应的配置数据。
2) 回调模式:查询是不是有点麻烦啊,于是考虑回调吧,回调也不等于是jsonp,你也可以直接请求一个静态js,只不过比较死板的,这个js里面已经hardcode了一个函数调用,比如说:
foobar ( 参数啊,配置数据啊 );
然后你在caller的这个页面(也就是创建动态script的页面)定义一个函数:
foobar( arg1, arg2){你对上面传入的参数的各种处理。}
好的,说道jsonp吧,jsonp即使让动态服务器根据页面请求参数拼接一个js函数调用语句
比如说,请求的url是这样的: http://www.b.com/data.jsp?jsoncallback=foobar
那么data.jsp, 会使用一个java语句拼接一个函数foobar的调用
resp.writeln("foobar(" + jsondata.toString() + "); ";
一旦浏览器的script标签加载完毕,发现收到这个data.jsp的响应数据刚好是一段js代码,刚好是调用自己上文定义的一个函数,真是太好了。
<script> function foobar(jsondata){ // process jsondata } </script> <!-- 下面的标签加载完毕以后的等价就是一个foobar({...});的函数调用语句 --> <script src="http://www.b.com/data.jsp?jsoncallback=foobar" />