zoukankan      html  css  js  c++  java
  • 前端跨域(二):JSONP

    上一篇文章 前端跨域(一):CORS 实现了跨域的一种解决方案,IE8 和其他浏览器分别通过 XDomainRequest 和 XHR 对象原生支持 CORS。这次我将补一补 Web 服务中也非常流行的一种跨域技术——JSONP,同时,将复用上次的前端跨域场景。

    1. JSONP(JavaScript Object Notation with padding,填充式JSON/参数式JSON)

    【简单理解】:JSONP = 回调函数(Padding) + 数据(JSON),可以将 Padding 理解为回调函数,JSONP 则为被包含在函数调用中的 JSON。

    callback({ "name": "Nicholas" });
    

    【原理】:Ajax 的跨域受到“同源策略”的限制,但是像 <script><img> 标签带有 src 属性,都可不受限制地其他域中加载资源,JSONP 则是通过动态 <script> 元素来使用的。

    【实现方式】:回调函数是当响应到来时应该在页面中调用的函数,其名字一般在请求中指定。在请求完成后,即 JSONP 响应加载到页面中以后,就会立即执行。

    function handleResponse(response) {
    	alert(response.city);
    }
    
    var script = document.createElement('script');
    // 指定回调函数的名字为 handleResponse
    script.src = 'http://freegeoip.net/json/?callback=handleResponse';
    document.body.insertBefore(script, document.body.firstChild);
    

    【优点】:能够直接访问响应文本,支持在浏览器域服务器之间双向通信。
    【缺点】:JSONP 从其他域中加载代码执行,存在安全隐患,因此,使用时需要保障web服务安全可靠。

    2. 本地模拟 JSONP 跨域

    接下来让我们来一步一步实现 JSONP,从中我们也将看到,JSONP 跟 AJAX 毫无关系。

    (1)首先,如果不使用 JSONP,实现一个正常的函数调用:创建 2 个 <script> 标签,一个用来定义函数以便处理数据,另一个则用来进行函数调用。

    通过进行函数调用

    (2)接着,我们将第二个 <script> 标签中的函数调用放到单独的 js 文件中,更改一下传入参数,进行验证。

    通过引入 js 文件进行函数调用

    (3)到此为止, callback 函数是在本地的 js 文件中被调用的。现在,假设这个 js 文件在服务端,需要通过请求才能获得,则给 <script> 标签指定相应的 src 即可。

    Server 端:

    var http = require('http');
    
    http.createServer(function(req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        // 发送字符串,等客户端获得响应时,即会调用该函数
        res.end("callback('This is the callback from server.')");
    }).listen(8888);
    

    通过请求服务调用回调函数

    服务器写死的回调函数名称

    (4)上面的回调函数是在服务端写死的,而现实的情况,应该是客户端以参数的形式将回调函数名称传递给服务端,服务端获取这个变量,从而进行调用。这样,服务端就不用关心这个回调函数的名称是否改变了,而且前端也可以自行定义回调函数的名称。

    OK,既然要传参,就得约定参数 key 值,这也是JSONP中唯一需要前后端一起约定字段的地方

    通过在请求URL中加上查询参数实现JSONP

    Server:

    var http = require('http');
    var url = require('url');
    
    http.createServer(function(req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
    
        // 解析 url 参数
        var params = url.parse(req.url, true).query;
        // jsonpCallback 为前后端约定的字段,用于获取回调函数的名称
        res.end(params.jsonpCallback + "('This is JSONP.')");
    }).listen(8888);
    

    回调函数通过查询参数获得

    (5)最后一步:为了提高代码的灵活性,实现 <script> 标签动态插入

    <script>
        // 定义回调函数
        var cb = function(data) {
            var oDiv = document.getElementById('content');
            oDiv.innerHTML = data;
        }
    
        var url = 'http://localhost:8888?jsonpCallback=cb';
    
        // 创建 script 标签,并设置其 src 属性
        var script = document.createElement('script');
        script.src = url;
    
        // 插入 body,此时调用开始
        document.body.appendChild(script);
    </script>
    

    瞧,整个过程,我们并没有用到 XHR 对象,只是利用了 <script>src 属性,因此 JSONP 与 AJAX 并不是一回事儿。

    3. jQuery 实现 JSONP

    jQuery 是前端经常使用的库,因此有必要了解 JSONP 在 jQuery 中的使用方式。
    jQuery 将其包含在 $.ajax() 中,其中用到的具体有3个参数:

    dataType(默认:none) :预期服务器返回的数据类型('json', 'jsonp', 'xml', 'html', 'text')
    jsonp(默认:“callback”): JSONP回调查询参数的名称,即前后端约定的字段名
    jsonpCallback(默认:“jsonp{N}”) :全局JSONP回调函数的字符串(或返回的一个函数)名。设置该项能启用浏览器的缓存。

    Client:

    var oDiv = document.getElementById('content');
    
    // 定义回调函数
    // 只是用于服务端获取名称,也可以自行实现,从而在 `success` 中进行调用
    var cb = function() {};
    
    $.ajax({
        url: 'http://localhost:8888',
        type: 'get',
        dataType: 'jsonp',  // 预期服务器返回的数据类型
        jsonp: 'A_callback',  // 指定回调查询参数的名称,即前后端约定的字段,默认为“callback"
        jsonpCallback: 'cb',  // 指定回调函数名称
        cache: true,
        success: function(data) {   // jQuery 将 JSON 数据剥离出来,传入 success 和 error
            console.log(data);  // 'This is JSONP realized by jQuery.'
            oDiv.innerHTML = data;
        }
    });
    

    Server:不变

    var http = require('http');
    var url = require('url');
    
    http.createServer(function(req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
    
        // 解析 url 参数
        var params = url.parse(req.url, true).query;
        // A_callback 为前后端约定的字段,用于获取回调函数的名称
        res.end(params.A_callback+ "('This is JSONP realized by jQuery.')");
    }).listen(8888);
    

    jQuery实现JSONP

    jsonp 可省略,或设置为 false,则查询参数就不会出现在 URL 中了,但是回调函数的名称需要前后端约定,因为无法从请求中获取回调函数的名称,后端只能将名称写死。

    jsonpCallback 也可省略,jQuery 会自动生成一个随机字符串作为函数名,可以减少不必要的命名工作。

    4. 参考

    5分钟彻底明白 JSONP
    Understanding JSONP


  • 相关阅读:
    [资料]PHP中的__autoload
    [转]php 5.3新增的闭包语法介绍function() use() {}
    [资料]PHP中的ReflectionClass
    [资料]PHP中的命名空间
    Mysql Event
    PHP转换成对像
    [转]Win7自带便签怎么恢复内容
    [转]Windows7便笺妙用
    [转]ASP.NET下MVC1.0>2.0>3.0>4.0
    PHP类动态属性问题
  • 原文地址:https://www.cnblogs.com/Ruth92/p/7261725.html
Copyright © 2011-2022 走看看