jsonp是一种利用标签跨域获取数据的技术,仅支持get请求且需服务端返回指定格式的js调用代码。

JSONP(JSON with Padding)是一种利用 <script></script> 标签不受同源策略限制的特性,实现跨域数据获取的古老但有效的技术。它适用于不支持 CORS 的老旧系统(如 IE6–IE9、无 CORS 配置的后端服务),但仅支持 GET 请求,且需服务端配合返回特定格式的响应。
JSONP 的基本原理
浏览器允许动态插入 <script></script> 标签加载任意域名的 JS 文件,JSONP 正是利用这一点:前端定义一个全局回调函数,将函数名作为参数传给服务端;服务端返回一段可执行的 JS 代码,内容为调用该函数并传入 JSON 数据。
例如,请求:https://legacy-api.example.com/data?callback=handleResponse
服务端响应:handleResponse({"name": "张三", "age": 28});
只要页面中已定义 window.handleResponse,这段脚本执行后就会触发回调。
手动实现 JSONP 请求
无需第三方库,几行原生 JS 即可完成:
- 动态创建
<script></script>元素,设置src属性为带callback参数的 URL - 在全局作用域挂载临时回调函数,处理返回数据
- 请求完成后及时移除
<script></script>标签和全局函数,避免内存泄漏或重复触发
示例代码:
function jsonp(url, callbackName, success, error) {
const script = document.createElement('script');
window[callbackName] = function(data) {
success && success(data);
document.head.removeChild(script);
delete window[callbackName];
};
script.src = `${url}${url.includes('?') ? '&' : '?'}callback=${callbackName}`;
script.onerror = () => {
error && error(new Error('JSONP request failed'));
document.head.removeChild(script);
delete window[callbackName];
};
document.head.appendChild(script);
}
// 使用
jsonp(
'https://legacy-api.example.com/user',
'cb_' + Date.now(), // 避免命名冲突
(data) => console.log('收到数据:', data),
(err) => console.error('请求出错:', err)
);
使用 jQuery 的 $.ajax 支持 JSONP
jQuery 1.x/2.x 内置了对 JSONP 的封装,配置 dataType: 'jsonp' 即可自动处理回调名生成、脚本注入与清理:
- 默认使用
callback=?,jQuery 会自动生成唯一回调名(如jQuery123456789_1234567890) - 通过
jsonpCallback可指定固定函数名(需后端支持) - 注意:jQuery 3+ 已移除 JSONP 支持,仅兼容旧版本
示例:
$.ajax({
url: 'https://legacy-api.example.com/list',
dataType: 'jsonp',
jsonp: 'callback', // 请求参数名,默认 'callback'
success: function(data) {
console.log('成功:', data);
},
error: function(xhr, status, err) {
console.error('失败:', status, err);
}
});
服务端需满足的关键条件
JSONP 能否成功,**完全取决于后端是否按约定返回合法 JS 调用**:
- 必须接受
callback(或自定义名)作为查询参数 - 响应 Content-Type 应为
application/javascript或text/javascript - 响应体必须是「函数调用 + JSON 数据」,不能是纯 JSON 字符串
- 建议对
callback参数做白名单校验(如只允许字母数字下划线),防止 XSS
Node.js Express 示例(简版):
app.get('/api/data', (req, res) => {
const cb = req.query.callback;
const data = { message: 'Hello from legacy API' };
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(cb)) {
return res.status(400).send('Invalid callback name');
}
res.type('js').send(`${cb}(${JSON.stringify(data)});`);
});
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











