我理解JSON,但不了解JSONP。 Wikipedia's document on JSON是(曾)JSONP的热门搜索结果。它说:
JSONP或“带填充的JSON”是JSON扩展,其中前缀被指定为调用本身的输入参数。
咦?什么电话?这对我没有任何意义。 JSON是一种数据格式。没有电话。
2nd search result来自一个名叫Remy的人,他写了关于JSONP的文章:
JSONP是脚本标记注入,将响应从服务器传递到用户指定的函数。
我可以理解这一点,但它仍然没有任何意义。
那么什么是JSONP?它为什么被创建(它解决了什么问题)?为什么我会用它?
附录:我刚刚在维基百科上创建了a new page for JSONP;根据jvenema的回答,它现在对JSONP进行了清晰而全面的描述。
它实际上并不太复杂......
说你在域example.com
,并且你想要域example.net
。要做到这一点,你需要跨越域边界,在大多数浏览器领域都是禁忌。
绕过此限制的一项是<script>
标签。当您使用脚本标记时,将忽略域限制,但在正常情况下,您无法对结果执行任何操作,只会对脚本进行评估。
输入JSONP
。当您向启用了JSONP的服务器发出请求时,您会传递一个特殊参数,告诉服务器一些关于您的页面的信息。这样,服务器就能够以您的页面可以处理的方式很好地包装其响应。
例如,假设服务器需要一个名为callback
的参数来启用其JSONP功能。然后你的请求看起来像:
http://www.example.net/sample.aspx?callback=mycallback
如果没有JSONP,这可能会返回一些基本的JavaScript对象,如下所示:
{ foo: 'bar' }
但是,使用JSONP时,当服务器收到“callback”参数时,它会以稍微不同的方式包装结果,返回如下内容:
mycallback({ foo: 'bar' });
如您所见,它现在将调用您指定的方法。因此,在您的页面中,您定义了回调函数:
mycallback = function(data){
alert(data.foo);
};
现在,当加载脚本时,它将被评估,并且您的函数将被执行。 Voila,跨域请求!
值得注意的是JSONP的一个主要问题:你失去了很多对请求的控制权。例如,没有“好的”方法来获取正确的故障代码。结果,您最终使用计时器来监视请求等,这总是有点可疑。 JSONRequest的提议是一个很好的解决方案,允许跨域脚本编写,维护安全性,并允许适当控制请求。
这些天(2015年),CORS是推荐的方法与JSONRequest。 JSONP对于较旧的浏览器支持仍然有用,但鉴于安全隐患,除非您没有选择,否则CORS是更好的选择。
JSONP实际上是一个克服XMLHttpRequest相同域策略的简单技巧。 (如您所知,无法将AJAX(XMLHttpRequest)请求发送到其他域。)
所以 - 我们不得不使用XMLHttpRequest,而是使用脚本HTML标签,这些标签通常用于加载js文件,以便js从另一个域获取数据。听起来怪怪的?
事情是 - 结果脚本标签可以像XMLHttpRequest类似的方式使用!看一下这个:
script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data';
在加载数据后,您将得到一个如下所示的脚本段:
<script>
{['some string 1', 'some data', 'whatever data']}
</script>
但是这有点不方便,因为我们必须从脚本标记中获取此数组。所以JSONP创建者决定这会更好(并且它是):
script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.someWebApiServer.com/some-data?callback=my_callback';
注意那边的my_callback函数?所以 - 当JSONP服务器收到你的请求并找到回调参数 - 而不是返回普通的js数组时,它将返回:
my_callback({['some string 1', 'some data', 'whatever data']});
看看利润在哪里:现在我们得到自动回调(my_callback),一旦我们获得数据就会被触发。 这就是JSONP的全部知识:它是一个回调和脚本标签。
注意:这些是JSONP使用的简单示例,这些不是生产就绪脚本。
基本JavaScript示例(使用JSONP的简单Twitter提要)
<html>
<head>
</head>
<body>
<div id = 'twitterFeed'></div>
<script>
function myCallback(dataWeGotViaJsonp){
var text = '';
var len = dataWeGotViaJsonp.length;
for(var i=0;i<len;i++){
twitterEntry = dataWeGotViaJsonp[i];
text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
}
document.getElementById('twitterFeed').innerHTML = text;
}
</script>
<script type="text/javascript" src="http://twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script>
</body>
</html>
基本的jQuery示例(使用JSONP的简单Twitter提要)
<html>
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
$.ajax({
url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10',
dataType: 'jsonp',
success: function(dataWeGotViaJsonp){
var text = '';
var len = dataWeGotViaJsonp.length;
for(var i=0;i<len;i++){
twitterEntry = dataWeGotViaJsonp[i];
text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>'
}
$('#twitterFeed').html(text);
}
});
})
</script>
</head>
<body>
<div id = 'twitterFeed'></div>
</body>
</html>
JSONP代表带有填充的JSON。 (技术名称很差,因为它与大多数人认为的“填充”无关。)
JSONP的工作原理是构建一个“脚本”元素(在HTML标记中或通过JavaScript插入到DOM中),该元素请求远程数据服务位置。响应是一个javascript加载到您的浏览器上,其中包含预定义函数的名称以及传递的参数,即请求的JSON数据。当脚本执行时,该函数与JSON数据一起被调用,允许请求页面接收和处理数据。
进一步阅读访问:https://blogs.sap.com/2013/07/15/secret-behind-jsonp/
客户端代码片段
<!DOCTYPE html>
<html lang="en">
<head>
<title>AvLabz - CORS : The Secrets Behind JSONP </title>
<meta charset="UTF-8" />
</head>
<body>
<input type="text" id="username" placeholder="Enter Your Name"/>
<button type="submit" onclick="sendRequest()"> Send Request to Server </button>
<script>
"use strict";
//Construct the script tag at Runtime
function requestServerCall(url) {
var head = document.head;
var script = document.createElement("script");
script.setAttribute("src", url);
head.appendChild(script);
head.removeChild(script);
}
//Predefined callback function
function jsonpCallback(data) {
alert(data.message); // Response data from the server
}
//Reference to the input field
var username = document.getElementById("username");
//Send Request to Server
function sendRequest() {
// Edit with your Web Service URL
requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+"");
}
</script>
</body>
</html>
服务器端的PHP代码
<?php
header("Content-Type: application/javascript");
$callback = $_GET["callback"];
$message = $_GET["message"]." you got a response from server yipeee!!!";
$jsonResponse = "{\"message\":\"" . $message . "\"}";
echo $callback . "(" . $jsonResponse . ")";
?>
因为您可以要求服务器将前缀附加到返回的JSON对象。例如
function_prefix(json_object);
为了让浏览器以eval
“内联”JSON字符串作为表达式。这个技巧使服务器可以直接在客户端浏览器中“注入”javascript代码,并绕过“同源”限制。
换句话说,您可以进行跨域数据交换。
通常,XMLHttpRequest
不允许直接进行跨域数据交换(需要通过同一域中的服务器),而:
<script src="some_other_domain/some_data.js&prefix=function_prefix
>`人们可以从不同于原点的域访问数据。
另外值得注意的是:即使在尝试那种“技巧”之前服务器应被视为“可信”,也可以包含对象格式等可能发生变化的副作用。如果使用function_prefix
(即正确的js函数)来接收JSON对象,则所述函数可以在接受/进一步处理返回的数据之前执行检查。
JSONP是一个很好的解决跨域脚本错误的方法。您可以完全使用JS来使用JSONP服务,而无需在服务器端实现AJAX代理。
您可以使用b1t.co服务查看它的工作原理。这是一个免费的JSONP服务,可以帮助您缩小网址。以下是用于服务的网址:
http://b1t.co/Site/api/External/MakeUrlWithGet?callback=[resultsCallBack]&url=[escapedUrlToMinify]
例如,电话,http://b1t.co/Site/api/External/MakeUrlWithGet?callback=whateverJavascriptName&url=google.com
会回来的
whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"});
因此当这个get作为src加载到你的js中时,它会自动运行你应该实现的任何JavascriptName作为你的回调函数:
function minifyResultsCallBack(data)
{
document.getElementById("results").innerHTML = JSON.stringify(data);
}
要实际进行JSONP调用,可以通过多种方式(包括使用jQuery)来实现,但这里是一个纯JS示例:
function minify(urlToMinify)
{
url = escape(urlToMinify);
var s = document.createElement('script');
s.id = 'dynScript';
s.type='text/javascript';
s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url;
document.getElementsByTagName('head')[0].appendChild(s);
}
有关练习的分步示例和jsonp Web服务,请访问:this post
一个使用JSONP的简单示例。
client.html
<html>
<head>
</head>
body>
<input type="button" id="001" onclick=gO("getCompany") value="Company" />
<input type="button" id="002" onclick=gO("getPosition") value="Position"/>
<h3>
<div id="101">
</div>
</h3>
<script type="text/javascript">
var elem=document.getElementById("101");
function gO(callback){
script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://localhost/test/server.php?callback='+callback;
elem.appendChild(script);
elem.removeChild(script);
}
function getCompany(data){
var message="The company you work for is "+data.company +"<img src='"+data.image+"'/ >";
elem.innerHTML=message;
}
function getPosition(data){
var message="The position you are offered is "+data.position;
elem.innerHTML=message;
}
</script>
</body>
</html>
server.php
<?php
$callback=$_GET["callback"];
echo $callback;
if($callback=='getCompany')
$response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})";
else
$response="({\"position\":\"Development Intern\"})";
echo $response;
?>
在了解JSONP之前,您需要了解JSON格式和XML。目前,Web上最常用的数据格式是XML,但XML非常复杂。它使用户不方便处理嵌入在网页中的内容。
为了使JavaScript能够轻松交换数据,即使作为数据处理程序,我们也会根据JavaScript对象使用措辞并开发出简单的数据交换格式,即JSON。 JSON可以用作数据,也可以用作JavaScript程序。
JSON可以直接嵌入到JavaScript中,使用它们可以直接执行某些JSON程序,但由于安全限制,浏览器Sandbox机制会禁用跨域JSON代码执行。
为了使JSON可以在执行后传递,我们开发了一个JSONP。 JSONP通过JavaScript Callback功能和<script>标记绕过了浏览器的安全限制。
简而言之,它解释了JSONP是什么,它解决了什么问题(何时使用它)。
已经给出了很好的答案,我只需要在javascript中以代码块的形式提供我的文章(我还将包括更多现代和更好的跨源请求解决方案:带有HTTP标头的CORS):
JSONP:
1.client_jsonp.js
$.ajax({
url: "http://api_test_server.proudlygeek.c9.io/?callback=?",
dataType: "jsonp",
success: function(data) {
console.log(data);
}
});
2.server_jsonp.js
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var callback = url.parse(req.url, true).query.callback || "myCallback";
console.log(url.parse(req.url, true).query.callback);
var data = {
'name': "Gianpiero",
'last': "Fiorelli",
'age': 37
};
data = callback + '(' + JSON.stringify(data) + ');';
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(data);
});
server.listen(process.env.PORT, process.env.IP);
console.log('Server running at ' + process.env.PORT + ':' + process.env.IP);
HEARTS:
3.client_cors.js
$.ajax({
url: "http://api_test_server.proudlygeek.c9.io/",
success: function(data) {
console.log(data);
}
});
4.server_cors.js
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
console.log(req.headers);
var data = {
'name': "Gianpiero",
'last': "Fiorelli",
'age': 37
};
res.writeHead(200, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
});
res.end(JSON.stringify(data));
});
server.listen(process.env.PORT, process.env.IP);
console.log('Server running at ' + process.env.PORT + ':' + process.env.IP);
JSONP代表带有填充的JSON。
这是一个网站,有很好的例子,从最简单的使用这种技术到最先进的平面JavaScript的解释:
上面描述的我最喜欢的技术之一是Dynamic JSON Result,它允许在URL参数中将JSON发送到PHP文件,并让PHP文件根据它获得的信息返回JSON对象。
像jQuery also have facilities to use JSONP这样的工具:
jQuery.ajax({
url: "https://data.acgov.org/resource/k9se-aps6.json?city=Berkeley",
jsonp: "callbackName",
dataType: "jsonp"
}).done(
response => console.log(response)
);