JSONP原理与实现:解决跨域请求的脚本注入方案
本文详细解析JSONP(JSON with Padding)技术,旨在解决浏览器同源策略限制下的跨域数据获取问题。通过利用script标签不受同源策略限制的特性,将数据封装在回调函数中返回,实现了跨域通信。文章展示了从原生JavaScript动态创建script标签到jQuery封装实现的完整过程,并指出了潜在的安全风险。
JSONP原理与跨域问题
JSONP全称JSON with Padding,是解决跨域请求资源的一种方案。通常客户端通过Ajax与Web服务交互获取服务器数据,但若目标数据位于不同域,浏览器的同源策略会出于安全考虑阻止直接请求,导致无法跨域获取资源。例如在localhost域下的books.php尝试向test.com域的books.php发起GET请求以获取书籍列表,即构成跨域请求。
代码如下:
$.ajax({
type:'get',
url:'http://test.com/books.php'
});执行上述代码会报错:XMLHttpRequest cannot load http://test.com/books.php. Origin http://localhost is not allowed by Access-Control-Allow-Origin。JSONP正是为解决此问题而诞生。
JSONP实现机制
尽管存在同源策略限制,但HTML中并非所有资源都受此约束。为优化加载速度或节省流量,页面常引用Google或微软的jQuery CDN。此时可通过以下方式引入jQuery:
代码如下:
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
</script>iframe、img、style、script等元素的src属性可直接向不同域请求资源,JSONP正是利用script标签的这一特性来实现跨域数据获取。
假设localhost下的books.php需要获取test.com域的书籍列表,而test.com中书籍数据存储在books.xml文件中。
代码如下:
<?xml version="1.0"?>
<books>
<book name="JavaScript: The Defiitive Guide" publisher="O'Reilly Media, Inc.">
<author>David Flanagan</author>
</book>
<book name="PHP anf MySQL Web Development" publisher="Perason Education">
<author>Luke Welling</author>
<author>Laura Thomson</author>
</book>
<book name="HTTP: The Defiitive Guide" publisher="O'Reilly Media, Inc.">
<author>David Courley</author>
<author>Brian Totty</author>
</book>
</books>JavaScript无法直接解析books.xml,因此test.com需提供机制将XML转换为JSON格式(这也是JSONP名称的由来,尽管返回数据不一定是JSON,但JSON便于处理),并动态拼接JavaScript调用语句返回。本例直接使用PHP页面进行拼接。
test.com/bookservice.php
代码如下:
<?php
$path=$_SERVER["DOCUMENT_ROOT"].'/books.xml';
$json=json_encode(simplexml_load_file($path));
$callbackFn=$_GET['callback'];
echo "$callbackFn($json);"
?>上述代码首先将XML文件内容转换为JSON对象。
代码如下:
{"book":[
{"@attributes":{"name":"JavaScript: The Defiitive Guide","publisher":"O'Reilly Media, Inc."},"author":"David Flanagan"},
{"@attributes":{"name":"PHP anf MySQL Web Development","publisher":"Perason Education"},"author":["Luke Welling","Laura Thomson"]},
{"@attributes":{"name":"HTTP: The Defiitive Guide","publisher":"O'Reilly Media, Inc."},"author":["David Courley","Brian Totty"]}
]}随后将JSON数据拼接为一条JavaScript语句返回给localhost处理。由于test.com不知道具体的回调函数名,localhost需在请求URL中传入名为callback(名称可自定义,但需两端一致)的参数来指定回调函数。以下是localhost发送请求的方式:
原生JavaScript实现
localhost/books.php
代码如下:
<!DOCTYPE html>
<html>
<head>
<title>Books</title>
<?php include('/components/headerinclude.php');?></head>
<style type="text/css">
.book-title
{
font-size: 15px;
font-weight:bold;
margin-top:6px;
}
.book-info
{
color:#ccc;
font-style:italic;
border-bottom:dashed 1px #ccc;
}
</style>
</head>
<body>
<div style="margin:20px;">
<div style="font-size:16px;font-weight:bold;">Books</div>
<div id="books">
</div>
</div>
</body>
</html>目标是在id为books的div中展示所有书籍。首先定义一个用于处理数据的回调函数,结合前述JSON格式,代码如下:
代码如下:
function displayBooks(books){
var books=books.book;
var booksContainer=document.getElementById('books');
for(var i=0;i<books.length;i++){
var tmp=Array();
tmp.push('<div class="book-title">'+books[i]['@attributes'].name+'</div>');
tmp.push('<div class="book-info">');
tmp.push('<div>Publisher: '+books[i]['@attributes'].publisher+'</div>');
tmp.push('<div>Author(s): ');
if(typeof books[i].author=='string'){
tmp.push(books[i].author);
}else{
var authors=books[i].author;
for(var j=0;j<authors.length;j++){
tmp.push(authors[j]+' ');
}
}
tmp.push('</div>'); //end of author
tmp.push('</div>'); //end of book info
booksContainer.innerHTML+=tmp.join('');
}
}接下来是关键步骤:实现JSONP请求方法。
代码如下:
function getBooks(){
var script=document.createElement('script');
script.setAttribute('type','text/javascript');
script.setAttribute('src','http://test.com/bookservice.php?callback=displayBooks');
document.body.appendChild(script);
}
getBooks();在getBooks()方法中动态创建script标签,设置其src属性指向test.com提供的数据服务接口,并传入回调函数。通过Chrome控制台可观察到该请求。

通过上述方式,即可在localhost环境下获取test.com的书籍数据。

jQuery实现
jQuery封装实现
jQuery对JSONP进行了封装,将其集成在Ajax中。虽然两者机制不同,但jQuery提供了更便捷的调用方式。jQuery版本实现如下:
代码如下:
function getBooks(){
$.ajax({
type:'get',
url:'http://test.com/bookservice.php',
dataType:'jsonp',
jsonp:'callback',
jsonpCallback:'displayBooks'
});
}看起来与普通Ajax无异,但简化了操作,无需手动创建script标签。只需指定dataType为jsonp,并通过两个参数分别指定回调函数名。
安全性注意事项
使用JSONP存在一定安全风险。若请求的站点不可信,返回的方法调用中可能包含恶意代码。因此应仅向信任的站点发送请求。此外,XSS攻击常利用JSONP向站点注入恶意代码。
JS处理特殊字符时怎么安全生成JSON
2026-11-05 15:44:51
内部脚本与外部js文件的区别及优缺点对比
2026-11-05 14:42:19
JavaScript前端性能优化指南:提升页面加载速度与渲染效率
2026-11-05 13:48:26
主流JS反混淆工具对比:de4js、unminify与AST还原方案评测
2026-11-05 12:00:56
Nuxt.js 性能优化技巧:代码分割与组件懒加载
2026-11-03 23:32:56
相关标签:
