JSONP跨域原理全解析
JSONP(JSON with Padding)是一种绕过浏览器同源策略限制、实现跨域数据请求的“hack”式方案。其核心原理和流程如下:
-
同源策略限制
浏览器为了安全,只允许页面从与当前页面相同协议、域名、端口的服务器加载数据。而<script>
、<img>
、<link>
等标签对跨域不受同源策略限制——只要目标资源返回有效内容,浏览器就会加载并执行。 -
利用
<script>
标签跨域
JSONP 利用该特性:前端通过动态创建一个<script>
标签,设置其src
属性指向目标跨域接口,并带上一个回调函数名参数,比如:<script>function handle(data) {console.log('服务器返回的数据:', data);}var script = document.createElement('script');script.src = 'https://api.example.com/data?callback=handle';document.head.appendChild(script); </script>
-
服务器端“打包”返回
服务器接收到请求后,不是直接返回纯 JSON,而是把 JSON 数据“包裹”(padding)在指定的回调函数调用里,例如:handle({"name": "Alice","age": 30 });
浏览器加载这个脚本时,就会立即执行
handle(...)
,把数据当作参数传入页面上事先定义好的回调函数。 -
流程图示
- 页面定义全局回调函数
handle
。 - 页面动态插入
<script src="...callback=handle">
。 - 浏览器向跨域服务器发送 GET 请求。
- 服务器将 JSON 数据封装成
handle(JSON)
格式的脚本返回。 - 浏览器下载并执行该脚本,触发全局回调函数,拿到数据。
- 页面定义全局回调函数
-
优缺点
- 优点
- 简单,无需 CORS 支持即可跨域请求 GET 接口。
- 缺点
- 仅支持 GET 请求,不支持 POST、PUT 等。
- 安全性较差,容易受到 XSS 攻击(调用任意脚本)。
- 回调地狱:多个并发请求时需要管理不同回调名。
- 优点
-
现代替代
随着 CORS(跨域资源共享)和fetch
/XMLHttpRequest
支持跨域请求,JSONP 已被逐步淘汰,仅在极少数不支持 CORS 的老旧环境下使用。
示例代码
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>JSONP 示例</title><script>// 全局回调函数function jsonpCallback(data) {document.getElementById('output').textContent ='Hello, ' + data.name + ',你 ' + data.age + ' 岁了!';}// 动态加载 JSONP 脚本function loadData() {const script = document.createElement('script');script.src = 'https://api.example.com/user?callback=jsonpCallback';document.head.appendChild(script);}</script>
</head>
<body><button onclick="loadData()">获取用户信息</button><div id="output"></div>
</body>
</html>
上述例子中,当点击按钮时,会向 https://api.example.com/user?callback=jsonpCallback
发起跨域请求,服务器返回:
jsonpCallback({ "name": "Bob", "age": 25 });
浏览器执行该脚本,直接调用页面上的 jsonpCallback
,完成数据读取和展示。