🧠 一、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 同时请求(自动管理全局空间)
