什么是JSONP,它为何被创建?
技术背景
在Web开发中,浏览器存在同源策略限制,即浏览器不允许页面向不同源(协议、端口、主机任一不同)的服务器直接发起AJAX请求。例如,在 example.com
域名下的页面无法直接向 example.net
域名的服务器发起请求。这一限制是为了保护用户信息安全,防止恶意网站通过跨域请求获取用户敏感数据。但在实际开发中,有时确实需要从不同源的服务器获取数据,JSONP(JSON with Padding)就是为了解决这个问题而诞生的一种跨域数据交互技术。不过,JSONP也存在一些缺点,如今在大多数情况下,更推荐使用CORS(Cross-Origin Resource Sharing)来处理跨域请求。
实现步骤
1. 客户端创建script标签
客户端通过创建 <script>
标签来发起请求,因为 <script>
标签不受同源策略的限制。例如:
1 2 3 4
| var script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://www.example.net/sample.aspx?callback=mycallback'; document.getElementsByTagName('head')[0].appendChild(script);
|
2. 服务器处理请求
服务器接收到请求后,会检查是否包含 callback
参数。如果包含,服务器会将返回的JSON数据包装在回调函数中。例如,原本返回的JSON数据为 { foo: 'bar' }
,在JSONP请求下,服务器会返回 mycallback({ foo: 'bar' });
。
3. 客户端定义回调函数
客户端需要在全局作用域中定义与 callback
参数值相同的回调函数,用于处理服务器返回的数据。例如:
1 2 3
| function mycallback(data) { alert(data.foo); }
|
当 <script>
标签加载完成后,会自动执行回调函数,从而实现跨域数据的处理。
核心代码
纯JavaScript实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <!DOCTYPE html> <html lang="en"> <head> <title>JSONP示例</title> <meta charset="UTF-8" /> </head> <body> <input type="text" id="username" placeholder="Enter Your Name" /> <button type="submit" onclick="sendRequest()"> Send Request to Server </button> <script> "use strict"; function requestServerCall(url) { var head = document.head; var script = document.createElement("script"); script.setAttribute("src", url); head.appendChild(script); head.removeChild(script); }
function jsonpCallback(data) { alert(data.message); }
var username = document.getElementById("username");
function sendRequest() { requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message=" + username.value + ""); } </script> </body> </html>
|
服务器端PHP代码
1 2 3 4 5 6 7
| <?php header("Content-Type: application/javascript"); $callback = $_GET["callback"]; $message = $_GET["message"] . " you got a response from server yipeee!!!"; $jsonResponse = "{\"message\":\"" . $message . "\"}"; echo $callback . "(" . $jsonResponse . ")"; ?>
|
jQuery实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <html> <head> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> <script> $(document).ready(function () { $.ajax({ url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10', dataType: 'jsonp', success: function (dataWeGotViaJsonp) { var text = ''; var len = dataWeGotViaJsonp.length; for (var i = 0; i < len; i++) { var twitterEntry = dataWeGotViaJsonp[i]; text += '<p><img src = "' + twitterEntry.user.profile_image_url_https + '"/>' + twitterEntry['text'] + '</p>'; } $('#twitterFeed').html(text); } }); }) </script> </head> <body> <div id="twitterFeed"></div> </body> </html>
|
最佳实践
- 使用CORS替代:在现代Web开发中,尽量使用CORS来处理跨域请求。CORS是一种更安全、更标准的跨域解决方案,服务器可以通过设置响应头来控制哪些源可以访问资源。
- 验证回调函数名:在服务器端,应该对客户端传递的回调函数名进行严格验证,防止XSS攻击。例如,只允许合法的函数名,避免使用用户输入的原始值。
- 设置超时:由于JSONP请求没有标准的错误处理机制,可以设置超时来处理请求失败的情况。
常见问题
1. 只能进行GET请求
JSONP本质上是通过 <script>
标签发起请求,而 <script>
标签只能发起GET请求,因此无法使用JSONP进行POST等其他类型的请求。
2. 缺乏错误处理
JSONP请求没有标准的错误处理机制,无法像AJAX请求那样获取详细的错误信息。可以通过设置超时来处理请求失败的情况,但这种方法不够完善。
3. 安全风险
由于JSONP允许服务器返回可执行的JavaScript代码,如果服务器被攻击,可能会返回恶意代码,导致用户信息泄露。因此,在使用JSONP时,必须确保服务器的安全性。