json、jsonp跨域请求数据小结
环境:DotNet4.5 MVC4.0
最近在做项目的时候遇到跨域请求的问题,主要是对json和jsonp的使用,做个小总结,小的初学,请各位大牛轻虐。
就环境而言呢,实际上项目是部署在同一服务器上的几个solution,现在的需求是想要访问另一solution中的API,返回Json(model,jsonbehavior.allowget)。满怀自信的写好ajax,type=“get”,data-type=“json”,url=“xxx.xxx.xxx.xxx/api/func",然后处理下success的json数据,append的到页面上,启动,一气呵成,OK,显示正常,发布部署到服务器,浏览,数据为空,呵呵了。
看了下发现我的电脑用的是IE11,服务器是IE9,浏览器不兼容,好的,找个IE9的电脑,调试下程序,在ajax的error事件里抛出statusTXT,报”NO Tranport“异常,果断问度娘,找到一句话,jquery.support.cors=true;启动,数据出来了,NICE,打完收工。
第二天bos说IE6报js错误,蛋碎一地,自己试了下,发现除了IE9+,其他浏览器均无法显示数据,Very Very Nice,然后各种调试,get、post和json、html各种组合,全部NO反应,看来跨域请求json数据还是有点不同的,基于同源策略的蛋疼特性,所以转投jsonp的怀抱。
研究以后,这里先说明一下jsonp和json的区别,虽然被jquery打包塞进了ajax的数据类型中,不过严格来说jsonp并不是一种数据格式,而是一种数据访问的方式,被某些大牛利用html一些特性做出来主要用于跨域数据传递的解决。由于同源策略的限制,页面使用的资源通常只能访问本域内有的,但是某些标签除外,比如说<script>和<iframe>标签中的src属性,使得它们可以直接跨域调用资源,比如说引用Jquery.min.js,我们可以直接引用google的js,而jsonp就是利用这种特性来进行跨域资源访问的。
查了查jquery的api,主要多了个callback参数,用于传递回调方法的名称,大爷的,关键部分不说。好吧,先试试,直接把数据格式改成jsonp,启动,JS报错,返回的json数据冒号附近有语法错误,缺少分号”;“。咦,难道是我api里返回的json数据格式冗余?好的,各种精简,没有的全部干掉,需要啥返回啥,再次运行,一样报错,好吧,上网查。
注意到网上的一些处理方法,服务器接到请求后在js里生成类似于<script>object{"xxx":"xxx"}</script>的html语句块,突然意识到上面说的,jsonp是利用<script>的src特性来完成跨域数据访问的,所以这里返回的应该是javascript而不是直接返回json,但是网上是在js里用createElement生成的html,难道我要在Controller里手动拼接?nope,这里用了一个webapi JavaScriptSerializer,使用Serialize方法直接将数据处理为javascript,然后response回去,类似于json api的序列化方法。生成启动,OK,数据出来了,试了搜狗、火狐、360浏览器,全部没有问题,奶奶的,终于可以歇口气了,上个厕所去,回见。
补充说明:
经过一段时间的使用,这里再详细说明一下jsonp的使用特性,上文已经说明,使用jsonp请求json数据实际上实在请求跨域的js资源,你可以返回字符串,datatable等等,那么返回的数据会作为js加载到页面当中,比如说我返回一个string:“hello world”,那么实际上在页面的脚本上添加了下面这样的东西。
<script> hello world </script>同样,如果我们json的数据那么它在页面加载的结果就是:
<script> {string:"hello world"} </script>显而易见,这必然是报错的结果,我们肯定不能直接在写js的时候写一个字符串上去,那么如何解决这个问题,这就是为什么要传一个callback参数过去。如何把这个字符串放到js上而且不报错,还要为我们所用,那么需要我们把它当成一个方法的参数传回来,而这个方法就是我们指定的callback参数,即回调函数。实际上我们可以把这个回调函数先放一边,假设我们传回来这样一个字符串"fun('hello world')",那么在页面加载的js就是
<script> fun("hello world") </script>那么我们要做的就是提前定义好一个方法fun(string){},至于json该怎么用就显而易见了吧。那么大多数情况下API可能不是我们自己写的,我们不能要求那边每次按我们的要求返回什么样的字符串,所以就要用到callback参数,就是提前把我们想让他返回结果后调用的方法传给他,那么他就可以通过request解析到这个方法名,然后拼出结果返回给我们就可以了。
上面我用了一个webAPI来将json字符串解析为js,然后就可以直接返回到ajax请求的success(string)方法里,其实原理是一样的,只是某些操作被jquery自动执行了。如果我们不指定callback参数的值,其实jquery会帮我们自动生成一个,类似于“jquery000000000”,后面的这些数字是用来唯一区别的,至于是时间戳还是什么的我就没有去研究了,通过上面的webAPI自动帮我们解析,传回结果,然后这个方法会替代success方法执行,好处就是不用我们自己去想一个方法名了,看起来就和普通的ajax请求很像了。