JSONP是什么?
JSONP 不是一门编程语言,也不是什么特别的技术,它更像一个漏洞,程序员可以利用这个漏洞,实现跨域(可以简单理解为跨域名)传输数据。虽然 JSONP 与 JSON 看起来很像,但它们却是完全不同的,本节我们就来简单介绍以下 JSONP。
在介绍 JSONP 之前,先来介绍一下浏览器的同源策略。
所谓同源是指域名、协议、端口都相同。以 http://c.biancheng.net:80/ 为例,c.biancheng.net 为域名,http 为协议,80 为端口(提示:80 为默认端口,可以省略,若为其它端口则必须显示定义)。
为了安全,浏览器不允许进行跨域请求。当我们通过 Ajax 在网页和服务器之间发送或接收数据时,需要保证网页与所请求的地址是同源的,否则无法请求成功。例如 http://c.biancheng.net/ 下的网页,只能与同在 http://c.biancheng.net/ 下的程序进行交互,无法与 https://www.baidu.com/ 下的程序进行交互。
同源策略可以防止 JavaScript 脚本从您的网站中读取数据,并将数据发送到其它的网站。如果没有同源策略,很有可能会有恶意的程序泄露您网站中的内容。
虽然同源策略在一定程度上提高了网站的安全,但也会给程序员带来一些麻烦,例如在访问一些开发接口时,由于同源策略的存在,会调用失败。要解决这种问题就需要用到跨域,跨域的方法有许多种,其中最经典的就是 JSONP。
在进行 Ajax 请求时,由于同源策略的影响,不能进行跨域请求,而
JSONP 的优点是兼容性好,在一些老旧的浏览器种也可以运行,但它的缺点也非常明显,那就是只能进行 GET 请求。
使用
另外,返回的内容也不能是一段纯 JSON 的数据,因为 JSON 数据会自动转换为一个 JavaScript 对象,但不将其分配给变量或者传递给函数,我们也无法拿来使用。
因此,我们可以在请求中提供一个回调函数(被作为参数传递的函数,等同于一般函数),然后通过服务器返回这个函数,并将要返回的 JSON 数据作为函数的参数一同返回,这样
在介绍 JSONP 之前,先来介绍一下浏览器的同源策略。
同源策略
同源策略是由 Netscape(网景)提出的一个著名的安全策略,所有支持 JavaScript 的浏览器都支持这个策略。所谓同源是指域名、协议、端口都相同。以 http://c.biancheng.net:80/ 为例,c.biancheng.net 为域名,http 为协议,80 为端口(提示:80 为默认端口,可以省略,若为其它端口则必须显示定义)。
为了安全,浏览器不允许进行跨域请求。当我们通过 Ajax 在网页和服务器之间发送或接收数据时,需要保证网页与所请求的地址是同源的,否则无法请求成功。例如 http://c.biancheng.net/ 下的网页,只能与同在 http://c.biancheng.net/ 下的程序进行交互,无法与 https://www.baidu.com/ 下的程序进行交互。
同源策略可以防止 JavaScript 脚本从您的网站中读取数据,并将数据发送到其它的网站。如果没有同源策略,很有可能会有恶意的程序泄露您网站中的内容。
虽然同源策略在一定程度上提高了网站的安全,但也会给程序员带来一些麻烦,例如在访问一些开发接口时,由于同源策略的存在,会调用失败。要解决这种问题就需要用到跨域,跨域的方法有许多种,其中最经典的就是 JSONP。
什么是 JSONP?
JSONP 全称“JSON with Padding”,译为“带回调的 JSON”,它是 JSON 的一种使用模式。通过 JSONP 可以绕过浏览器的同源策略,进行跨域请求。在进行 Ajax 请求时,由于同源策略的影响,不能进行跨域请求,而
<script>
标签的 src 属性却可以加载跨域的 JavaScript 脚本,JSONP 就是利用这一特性实现的。与普通的 Ajax 请求不同,在使用 JSONP 进行跨域请求时,服务器不再返回 JSON 格式的数据,而是返回一段调用某个函数的 JavaScript 代码,在 src 属性种调用,来实现跨域。JSONP 的优点是兼容性好,在一些老旧的浏览器种也可以运行,但它的缺点也非常明显,那就是只能进行 GET 请求。
如何实现 JSONP
假设我们要从网站 localhost:8080 向服务器 localhost:8081 下的发送请求,并在服务器返回如下内容:{"name":"C语言中文网", "url":"http://c.biancheng.net/"}
如果直接发送 Ajax 请求,由于同源策略的存在,请求会被阻止,因为网站和服务器不同源。示例代码如下:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript</title> </head> <body> <div id="result"></div> <button type="button" onclick="sendAjax()">发送请求</button> <script> function sendAjax() { // 创建 XMLHttpRequest 对象 var request = new XMLHttpRequest(); // 实例化请求对象 request.open("GET", "http://localhost:8081/test.php"); // 监听 readyState 的变化 request.onreadystatechange = function() { // 检查请求是否成功 if(this.readyState === 4 && this.status === 200) { // 将来自服务器的响应插入当前页面 document.getElementById("result").innerHTML = this.responseText; } }; // 将请求发送到服务器 request.send(); } </script> </body> </html>点击页面的“发送请求”按钮,会返回如下错误:
Access to XMLHttpRequest at 'http://localhost:8081/test.php' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET http://localhost:8081/test.php net::ERR_FAILED
使用
<script>
标签,将标签的 src 属性设置为要请求的地址,如下所示:<script src="http://localhost:8081/test.php"></script>
这时您会发现,<script>
标签会自动解析并执行返回的内容,如果这些内容不是完整的 JavaScript 代码,程序就会报错,所有在进行 JSONP 跨域请求时,需要保证服务器返回一段完整的 JavaScript 代码。另外,返回的内容也不能是一段纯 JSON 的数据,因为 JSON 数据会自动转换为一个 JavaScript 对象,但不将其分配给变量或者传递给函数,我们也无法拿来使用。
因此,我们可以在请求中提供一个回调函数(被作为参数传递的函数,等同于一般函数),然后通过服务器返回这个函数,并将要返回的 JSON 数据作为函数的参数一同返回,这样
<script>
标签在解析并执行返回内容是就会自动调用这个函数。示例代码如下:<script src="http://localhost:8081/test.php?callback=showJsonData"></script>
服务器 http://localhost:8081/ 的完整代码如下所示:<?php $data = array('name'=>'C语言中文网', 'url'=>'http://c.biancheng.net/'); // 定义一个数组,其中包含要返回的内容 $callback = $_GET['callback']; // 接收请求中的回调函数 echo $callback."(".json_encode($data).")"; // 将上面的数组转换为 JSON 格式,然后拼接到函数中,作为函数的参数,返回给前端 return; // 阻止程序向下继续运行 ?>网站 localhost:8080 的完整代码如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript</title> </head> <body> <script> function showJsonData(data){ console.log(data); } </script> <script src="http://localhost:8081/test.php?callback=showJsonData"></script> </body> </html>运行结果如下:
{name: 'C语言中文网', url: 'http://c.biancheng.net/'}
总结
通过 JSONP,您可以避开浏览器的同源策略,进行跨域请求。JSONP 是利用 HTML 标签的 src 属性引用资源不受同源策影响的特性来实现的,实现步骤如下:- 在请求地址中拼接一个回调函数,得到一个新的地址,将这个新地址赋值给 <script> 标签的 src 属性;
- 服务器接收这个回调函数,并向函数中注入参数,然后以字符串的形式返回这个函数以及其中的参数;
- <script> 在接收到返回内容后,会将内容当作是一段 JavaScript 代码,自动执行。
注意:服务器返回的内容,必须是一段可执行的 JavaScript 代码,不能是其它内容。