这是我为那些需要的人所做的ELI5(像我一样解释我)尝试。
TL;博士
JSONP是为了绕过浏览器中的安全限制而发明的一个老把戏,该限制禁止我们获取不同于我们自己的网站/服务器(称为不同的源1)中的数据。
该技巧通过使用<script>标签从其他地方加载JSON(例如:{“city”:“Barcelona”})来实现,这将向我们发送封装在函数中的数据,即实际的JSONP(“带填充的JSON”):
tourismJSONP({"city":"Barcelona"})
通过这种方式接收数据,我们可以在旅游JSONP功能中使用数据。JSONP是一种糟糕的做法,不再需要,不要使用它(请在最后阅读)。
问题是
假设我们想在我们的web.com上使用另一个web.com上托管的一些JSON数据(或任何原始数据)。如果我们要使用GET请求(想想XMLHttpRequest,或fetch调用,$.ajax等),我们的浏览器会告诉我们,这是不允许的,并且会出现以下错误:
这是一个内容安全策略限制错误,旨在保护用户免受某些攻击。您应该正确配置它(请参见末尾)。
JSONP技巧对我们有何帮助?好吧,<script>标签不受整个服务器(origin1)的限制!这就是为什么我们可以从任何服务器加载像jQuery或GoogleMaps这样的库。
重要的一点是:如果你仔细想想,这些库是实际的、可运行的JS代码(通常是一个包含所有逻辑的大型函数)。但原始数据不是代码。没有什么可跑的;这只是纯文本。
因此,浏览器将下载<script>标记所指向的数据,在处理时,它会理所当然地抱怨:
这是我们装的垃圾吗?这不是代码。我不会计算!
旧的JSONP黑客
如果我们能让纯文本以某种方式运行,我们就能在运行时获取它。我们需要另一个web.com将其作为代码发送,因此当下载时,浏览器将运行它。我们只需要两件事:1)以可以运行的方式获取数据,2)在客户端中编写一些代码,以便在数据运行时调用我们的函数并使用数据。
对于1)如果外部服务器是JSONP友好的,我们将要求提供如下数据:
<script src="https://anotherweb.com/api/tourism-data.json?myCallback=tourismJSONP"></script>
所以我们会收到这样的信息:
tourismJSONP({"city":"Barcelona"})
这使得我们可以使用JS代码进行交互。
根据2),我们需要在代码中编写一个同名函数,如下所示:
function tourismJSONP(data){
alert(data.city); // "Barcelona"
}
浏览器将下载JSONP并运行它,它调用我们的函数,其中参数数据将是来自另一个web.com的JSON数据。我们现在可以随心所欲地处理数据。
不要使用JSONP,使用CORS
JSONP是一种跨站点黑客,有一些缺点:
我们只能执行GET请求由于这是一个由简单脚本标记触发的GET请求,因此我们不会得到有用的错误或进度信息还有一些安全问题,比如在客户端JS代码中运行,可能会被更改为恶意负载它只解决了JSON数据的问题,但同源安全策略适用于其他数据(WebFonts、使用drawImage()绘制的图像/视频…)它既不优雅,也不可读。
重要的是现在没有必要使用它。
您应该在这里阅读CORS,但其要点是:
跨源资源共享(CORS)是一种使用额外的HTTP头,告诉浏览器提供web应用程序在一个源上运行,从另一个源访问所选资源起源当web应用程序执行跨源HTTP请求时请求具有不同来源(域、协议或端口)。
起源由三个方面定义:协议、端口和主机。所以https://web.com与http://web.com(不同的协议)https://web.com:8081(不同的港口),显然https://thatotherweb.net(不同主机)