这篇答案已经超过六年了。虽然JSONP的概念和应用没有改变(即答案的细节仍然有效),但是你应该尽可能使用CORS(即你的服务器或API支持它,并且浏览器支持足够),因为JSONP存在固有的安全风险。
JSONP(带填充的JSON)是一种常用的方法,用于绕过Web浏览器中的跨域策略。(您不被允许通过AJAX请求与浏览器视为在不同服务器上的网页通信。)
JSON和JSONP在客户端和服务器上的行为不同。 JSONP请求不使用XMLHTTPRequest
和相关的浏览器方法进行调度。相反,创建了一个<script>
标签,其源设置为目标URL。然后将此脚本标记添加到DOM中(通常位于<head>
元素内部)。
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// success
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
JSON响应和JSONP响应的区别在于,JSONP响应对象作为回调函数的参数传递。
{ "bar": "baz" }
foo( { "bar": "baz" } );
JSON.parse
替换为eval
的举措向后倒退了很长一段路程。 - Levi HaskellXMLHttpRequest
之外提供支持(请注意,这个回答是来自2010年!)。考虑到微软已经不再支持这些浏览器,并考虑到JSONP带来的安全隐患,应该尽可能使用CORS(如果可用)。 - Matt假设你有一个URL,它提供了JSON格式的数据,例如:
{'field': 'value'}
假设你有一个类似的URL,但使用了JSONP,并且传递了回调函数名字'myCallback'(通常通过添加查询参数'callback'实现,例如http://example.com/dataSource?callback=myCallback
)。那么它将返回:
myCallback({'field':'value'})
这不仅是一个对象,而实际上可以执行的代码。因此,如果你在页面其他地方定义了一个叫做myFunction
的函数并执行这个脚本,它将被调用并带有来自URL的数据。
很酷的是:你可以创建一个脚本标签,并将包含callback
参数的URL作为src
属性使用,浏览器会运行它。这意味着你可以规避“同源策略”(因为浏览器允许你从页面域之外的源运行脚本标签)。
这就是当你发起一个ajax请求时jQuery所做的事情(使用dataType
属性设置值为'jsonp'的.ajax
)。例如:
$.ajax({
url: 'http://example.com/datasource',
dataType: 'jsonp',
success: function(data) {
// your code to handle data here
}
});
在这里,jQuery会处理回调函数名称和查询参数 - 使API与其他ajax调用相同。但与其他类型的ajax请求不同,正如前面提到的,你不受限于从与你的页面相同的来源获取数据。
JSONP是绕过浏览器的同源策略的一种方法。怎么做呢?像这样:
这里的目标是向otherdomain.com
发出请求并在响应中弹出名称。通常,我们会使用AJAX请求:
$.get('otherdomain.com', function (response) {
var name = response.name;
alert(name);
});
然而,由于请求发往不同的域名,因此它将无法工作。
我们可以使用<script>
标签来进行请求。无论是<script src="otherdomain.com"></script>
还是$.get('otherdomain.com')
都将导致发送相同的请求:
GET otherdomain.com
问:但是如果我们使用<script>
标签,我们怎么才能访问响应内容呢?如果我们想要弹出它,我们需要访问它。
答:嗯,我们做不到。但是这里有一个解决方法——定义一个使用响应的函数,然后告诉服务器用调用我们的函数并把响应作为其参数的JavaScript来响应。
问:但是如果服务器不愿意这样做,只想向我们返回JSON怎么办?
答:那么我们将无法使用它。JSONP需要服务器的合作。
问:必须使用<script>
标签真的很丑陋。
答:像jQuery这样的库使它更美观。例如:
$.ajax({
url: "http://otherdomain.com",
jsonp: "callback",
dataType: "jsonp",
success: function( response ) {
console.log( response );
}
});
它通过动态创建 <script>
标签 DOM 元素来工作。
问: <script>
标签只能发出 GET 请求 - 如果我们想要发出 POST 请求怎么办?
答:那么 JSONP 对我们就没用了。
问:那很好,我只想发出 GET 请求。JSONP 真的很棒,我打算去使用它 - 谢谢!
答:实际上,它并不是那么棒。它真的只是一个 hack。并且它并不安全。现在 CORS 可用后,应该尽可能使用它。
<script src="url?callback=function_name">
。