JSONP 不是一门编程语言,也不是什么特别的技术,它更像一个漏洞,程序员可以利用这个漏洞,实现跨域(可以简单理解为跨域名)传输数据。虽然 JSONP 与 JSON 看起来很像,但它们却是完全不同的,本节我们就来简单介绍以下 JSONP。
在介绍 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 全称“JSON with Padding”,译为“带回调的 JSON”,它是 JSON 的一种使用模式。通过 JSONP 可以绕过浏览器的同源策略,进行跨域请求。
在进行 Ajax 请求时,由于同源策略的影响,不能进行跨域请求,而 标签的 src 属性却可以加载跨域的 JavaScript 脚本,JSONP 就是利用这一特性实现的。与普通的 Ajax 请求不同,在使用 JSONP 进行跨域请求时,服务器不再返回 JSON 格式的数据,而是返回一段调用某个函数的 JavaScript 代码,在
src
属性种调用,来实现跨域。
JSONP 的优点是兼容性好,在一些老旧的浏览器种也可以运行,但它的缺点也非常明显,那就是只能进行 GET 请求。
假设我们要从网站 localhost:8080 向服务器 localhost:8081 下的发送请求,并在服务器返回如下内容:
{"name":"C语言中文网", "url":"http://c.biancheng.net/"}
如果直接发送 Ajax 请求,由于同源策略的存在,请求会被阻止,因为网站和服务器不同源。示例代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScripttitle>
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
想要成功从服务器中获取数据,就可以使用我们上面介绍的 JSON 来实现,实现步骤如下:
使用 标签,将标签的
src
属性设置为要请求的地址,如下所示:
<script src="http://localhost:8081/test.php"></script>
这时您会发现,
另外,返回的内容也不能是一段纯 JSON 的数据,因为 JSON 数据会自动转换为一个 JavaScript 对象,但不将其分配给变量或者传递给函数,我们也无法拿来使用。
因此,我们可以在请求中提供一个回调函数(被作为参数传递的函数,等同于一般函数),然后通过服务器返回这个函数,并将要返回的 JSON 数据作为函数的参数一同返回,这样 标签在解析并执行返回内容是就会自动调用这个函数。示例代码如下:
<script src="http://localhost:8081/test.php?callback=showJsonData"></script>
服务器 http://localhost:8081/ 的完整代码如下所示:
$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>JavaScripttitle>
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 属性引用资源不受同源策影响的特性来实现的,实现步骤如下:
标签的 src
属性;
在接收到返回内容后,会将内容当作是一段 JavaScript 代码,自动执行。注意:服务器返回的内容,必须是一段可执行的 JavaScript 代码,不能是其它内容。