为什么需要jsonp
同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。
其实说白了就是脚本不支持跨域访问
那怎么办
一:是让 Web 页面向它源自的 Web 服务器请求数据,并且让 Web 服务器像代理一样将请求转发给真正的第三方服务器。尽管该技术获得了普遍使用,但它是不可伸缩的。另一种方式是使用框架要素在当前 Web 页面中创建新区域,并且使用 GET
请求获取任何第三方资源。不过,获取资源后,框架中的内容会受到同源策略的限制。
二:更理想方法是在 Web 页面中插入动态脚本元素,该页面源指向其他域中的服务 URL 并且在自身脚本中获取数据。脚本加载时它开始执行。该方法是可行的,因为同源策略不阻止动态脚本插入,并且将脚本看作是从提供 Web 页面的域上加载的。但如果该脚本尝试从另一个域上加载文档,就不会成功。幸运的是,通过添加 JavaScript Object Notation (JSON) 可以改进该技术。
JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
其原理很简单,客户端生成一方法,并将其名称发到服务器,服务器返回 该方法调用的标签,并将数据传入进去。 类似于<script>CallBack({ 这里是数据 })</script> 这样的信息。
而且使用上强大的Jquery的时候会更简单,你会发现跟普通的ajax请求没太大区别。
实例:
这是之前单点登录使用到的jsonp,这里直接把它贴出来了。
function Login() { $.ajax({ type: "GET", url: "http://sso.tiexue.net/account/jsonlogon", data: "Username=" + $("#UserName").val() + "&Password=" + $("#Password").val() + "&ValidityDays=7&returnUrl=" + document.referrer, dataType: "jsonp", success: function (res) { if (res) { if (res.success && res.success == true) { if (res.returnurl && res.returnurl != "") { window.location.href = returnValue; } else { window.location.href = "http://m.junph.com"; } } else if (res && res.errors && res.errors != "") { $("#loginInfo").text(res.errors).show(); } } } }); }
通过监控我们可以得到这么个东西,具体的监控信息我就不贴出来,毕竟是公司内信息。negotiate.js个js文件,让我们来看看内容吧
jQuery18207690677059322467_1404976763158({"Url":"/797157b224e24e9da8e930644e22a645/arterySignalR","ConnectionToken":"AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAK6HmM0P+Q0+HxWeY1Eej1AAAAAACAAAAAAADZgAAwAAAABAAAAD4lgvnJP5Dq69Xhj31ctt7AAAAAASAAACgAAAAEAAAACqgv7fLBf+Vh5/dflOwOgMoAAAAW/5dV31Tn83EFf+n8c+QpdOAfTSmuepOHJ0VoLLwwe3hK72D07TwrBQAAACUMlWyaz8To7zTZgNK7lzw4Wf+Sg==","ConnectionId":"edf3a7f4-ad3f-4597-8dcd-1fbbe16c4304","KeepAliveTimeout":4.0,"DisconnectTimeout":6.0,"TryWebSockets":false,"ProtocolVersion":"1.3","TransportConnectTimeout":5.0});
很简单的一个方法调用,参数就是服务器端的json数据。
方法名为jsonp请求指定一个回调函数名。这个值将用来取代jQuery自动生成的随机函数名。这主要用来让jQuery生成度独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。你也可以在想让浏览器缓存GET请求的时候,指定这个回调函数名。
使用JSON的优点在于:
- 比XML轻了很多,没有那么多冗余的东西。
- JSON也是具有很好的可读性的,但是通常返回的都是压缩过后的。不像XML这样的浏览器可以直接显示,浏览器对于JSON的格式化的显示就需要借助一些插件了。
- 在JavaScript中处理JSON很简单。
- 其他语言例如PHP对于JSON的支持也不错。
JSON也有一些劣势:
- JSON在服务端语言的支持不像XML那么广泛,不过JSON.org上提供很多语言的库。
- 如果你使用eval()来解析的话,会容易出现安全问题。
尽管如此,JSON的优点还是很明显的。他是Ajax数据交互的很理想的数据格式。
JSONP 是构建 mashup 的强大技术,但不幸的是,它并不是所有跨域通信需求的万灵药。它有一些缺陷,在提交开发资源之前必须认真考虑它们。
第一,也是最重要的一点,没有关于 JSONP 调用的错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。
例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求。不过,等待一段时间还没有响应的话,就不用理它了。(未来的 jQuery 版本可能有终止 JSONP 请求的特性)。
JSONP 的另一个主要缺陷是被不信任的服务使用时会很危险。因为 JSONP 服务返回打包在函数调用中的 JSON 响应,而函数调用是由浏览器执行的,
这使宿主 Web 应用程序更容易受到各类攻击。如果打算使用 JSONP 服务,了解它能造成的威胁非常重要。