由于 jsonp 的工作方式,您的请求只触发了一次。
Jsonp 意味着从外部域向页面添加脚本标记,以绕过现代浏览器(以及截至 2011 年 4 月的 IE6 和 7)内置的跨站点脚本保护。为了让该脚本与页面上的其余脚本交互,正在加载的脚本需要调用页面上的函数。该函数必须存在于全局命名空间中,这意味着该名称只能有一个函数。换句话说,如果没有 JQuery,单个 jsonp 请求将如下所示:
<script>
function loadJson(json) {
// Read the json
}
</script>
<script src="//outsidedomain.com/something.js"></script>
something.js 看起来像这样:
loadJson({name:'Joe'})
在这种情况下,something.js 有一个硬编码的回调来加载它携带的 JSON,并且页面有一个硬编码的 loadJson 函数,等待像这样的脚本加载并调用它。
现在假设您希望能够从多个来源加载 json 并告知每个来源何时完成,或者甚至多次从同一来源加载 JSON,并且能够告知每个调用何时完成 - 即使一个调用被延迟这么长时间它完成在稍后的电话之后。这种硬编码方法不再适用,原因有两个:
每次加载 something.js 都会调用相同的 loadJson() 回调——你无法知道哪个请求对应哪个回复。
缓存——一旦你加载了 something.js,浏览器就不会再向服务器请求它——它只会从缓存中取回它,破坏你的计划。
您可以通过告诉服务器每次以不同方式包装 JSON 来解决这两个问题,简单的方法是将该信息传递到查询字符串参数中,例如?callback=loadJson12345
. 就好像您的页面看起来像这样:
<script>
function loadJson1(json) {
// Read the json
}
function loadJson2(json) {
// Read the json
}
</script>
<script src="//outsidedomain.com/something.js?callback=loadJson1"></script>
<script src="//outsidedomain.com/somethingelse.js?callback=loadJson2"></script>
使用 JQuery,这一切都被抽象为您看起来像对 $.ajax 的正常调用,这意味着您期望成功函数触发。为了确保每次 jsonp 加载都会触发正确的成功函数,JQuery 在全局命名空间中创建一个长的随机回调函数名称,如 JQuery1233432432432432,将其作为回调参数传递到查询字符串中,然后等待脚本加载。如果一切正常,加载的脚本会调用 JQuery 请求的回调函数,这反过来会从 $.ajax 调用中触发成功处理程序。
请注意,“正常工作”要求服务器端读取?callback
查询字符串参数并将其包含在响应中,例如?callback=joe
-> joe({...
。如果它是静态文件或服务器不以这种方式播放,您可能需要将该文件视为可缓存的 - 见下文。
缓存
如果您希望您的 json 缓存,您可以通过设置 cache: true 并将 jsonpCallback 属性设置为硬编码到可缓存 json 文件中的字符串来让 JQuery 做一些更接近我的第一个示例的操作。例如这个静态 json:
loadJoe({name:'Joe'})
可以像这样在 JQuery 中加载和缓存:
$.ajax({
url: '//outsidedomain.com/loadjoe.js',
dataType: 'jsonp',
cache: true,
jsonpCallback: 'loadJoe',
success: function(json) { ... }
});