🧠 一、JSONP 是什么?
项目 | 内容 |
---|---|
📌 全称 | JSON with Padding |
📍 用途 | 跨域请求数据的一种方式,绕过同源策略 |
📦 本质 | 通过 <script> 标签加载远程 JS 文件,这个文件执行一个回调函数并传入数据 |
🔍 二、JSONP 工作原理(层层递进)
-
定义全局回调函数
function jsonpCallback(data) { console.log(data); }
-
创建
<script>
标签并设置 srcscript.src = 'http://example.com/api?callback=jsonpCallback';
-
服务器响应 JavaScript 代码
jsonpCallback({ name: "Tom" });
-
浏览器执行返回的代码
- 调用了你定义的
jsonpCallback
函数 - 参数就是服务端返回的数据 ✅
- 调用了你定义的
❌ 三、常见错误
错误 | 原因 | 解决方式 |
---|---|---|
meta charset="UTF - 8" | 有空格,浏览器不识别 | 改为 UTF-8 |
回调函数未定义或冲突 | 多个请求使用相同名字 | 封装自动生成函数名 |
无法处理失败请求 | script 无 onerror 支持 | 使用 timeout 模拟失败处理 |
🔧 四、封装 JSONP 工具函数(现代化 Promise 版)
✅ 功能要点:
- 支持 URL 和参数拼接
- 自动生成唯一回调名
- 超时处理
- 自动清理
script
和回调函数 - 支持
Promise
,可以用.then
或async/await
✅ 封装代码:
function jsonp(url, params = {}, timeout = 5000) {return new Promise((resolve, reject) => {const callbackName = `jsonp_cb_${Date.now()}_${Math.random().toString().slice(2)}`;params.callback = callbackName;const queryString = Object.entries(params).map(([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');const script = document.createElement('script');script.src = `${url}?${queryString}`;script.async = true;window[callbackName] = (data) => {clearTimeout(timer);resolve(data);cleanup();};const timer = setTimeout(() => {reject(new Error('JSONP request timeout'));cleanup();}, timeout);function cleanup() {script.remove();delete window[callbackName];}document.body.appendChild(script);});
}
✅ 使用示例:
jsonp('http://example.com/api', { foo: 'bar' }).then(data => console.log('成功获取数据:', data)).catch(err => console.error('失败:', err));
🚀 五、JSONP 的优劣对比
优势 | 局限 |
---|---|
兼容老浏览器、实现跨域 | 只能 GET 请求 |
使用简单 | 安全性差(可能被注入恶意代码) |
不依赖 XMLHttpRequest | 不支持 HTTP 状态码、错误处理有限 |
🧩 六、扩展方向(可选封装能力)
- 支持取消请求(Abort)
- 支持 callback 参数名自定义(如
cb
、func
) - 支持多个 JSONP 同时请求(自动管理全局空间)