当前位置:首页 > 资讯 > info5 > 正文

解决Ajax 跨域问题 - JSONP原理解析

发表于: 2016-11-11   作者:qq_16415157   来源:转载   浏览:
摘要: 解决Ajax跨域问题-JSONP原理解析为什么会有跨域问题?-因为有同源策略同源策略是浏览器的一种安全策略,所谓同源指的是请求URL地址中的协议,域名和端口都相同,只要其中之一不相同就是跨域同源策略主要为了保证浏览器的安全性在同源策略下,浏览器**不允许**Ajax跨域获取服务器数据http://www.example.com/detail.html 跨域请求: http://api.exampl

解决Ajax 跨域问题 - JSONP原理解析

为什么会有跨域问题? - 因为有同源策略

  1. 同源策略是浏览器的一种安全策略,所谓同源指的是 请求URL地址中的 协议, 域名 端口 都相同,只要其中之一不相同就是跨域

  2. 同源策略主要为了保证浏览器的安全性

  3. 在同源策略下,浏览器**不允许**Ajax跨域获取服务器数据

    http://www.example.com/detail.html
    跨域请求:
        http://api.example.com/detail.html 域名不同
        http://www.example.com:8080/detail.html 端口不同
        http://api.example.com:8080/detail.html 域名、端口不同
        https://api.example.com/detail.html 协议、域名不同
        https://www.example.com:8080/detail.html 端口、协议不同

使用 jquery ajax-JSONP方式调用 解决跨域

虽然 jsonp 的实现跟 ajax 没有半毛钱关系jsonp是通过 script的src实现的(具体看后面的解析),但是最终目的都是向服务器请求数据然后回调,而且为了方便,所以jquery把 jsonp 也封装在了 $.ajax 方法中,调用方式与 ajax 调用方式略有区别,案例如下。

  • 测试jq_jsonp:

    目标请求地址, http://www.jepson.com/jq_jsonp.php

        <?php
            $cb = $_GET[ 'callback' ];    // 获取回调
            $arr = array( 'username' => 'zhangsan', 'password' => '123456' );
            echo $cb.'('. json_encode($arr) .');'; // 返回回调函数调用
    
            // 就是 jQuery1111011117830135968942_1478857963357({"username":"zhangsan","password":"123456"});
        ?>

    在 peter.com/jq_jsonp.html 里面,通过 Jquery ajax 方法, JSONP 方式调用,进行请求

        <script type="text/javascript" src="./jquery.js"></script> <script type="text/javascript"> $(function(){ $("#btn").click(function(){ $.ajax({ type:'get', url:'http://www.jepson.com/jq_jsonp.php', dataType:'jsonp', jsonp: 'callback', // 回调函数,后台get接收的变量名,默认 就callback // jsonpCallback: 'abc', 回调函数名,默认是一长串,jquery自动生成的,在请求url中可以看到 // 改不改无所谓,改短一点也只是 查看请求url的时候清晰一点而已 success:function(data){ console.log(data.username,data.password); // zhangsan 123456 }, error:function(data){ console.dir(data); console.log('error'); } }); }); }); </script> <body> <input type="button" value="点击" id="btn"> </body>

    可以看到,输出了 ‘zhangsan 123456’。

    注意:若后台没做获取回调,返回函数调用的工作,那么就会出错,进入 error方法。这是工作中常会遇到的错误,这里要注意

解决方式 JSONP 的原理解析

JSONP的原理:利用 script标签 的 src属性 进行跨域请求,服务器响应函数调用传参

这里了解 JSONP的原理 并进行测试,需要不同域,我这里是 apache 服务器,自己配置了 两个虚拟主机 做的。

两个域 代码所在域 http://www.peter.com/, 请求域 http://www.jepson.com/

JSONP基本原理 - 静态方法创建

我们通过下面静态方法创建的测试来看看JSONP解决跨域问题的基本原理
- 测试1:

目标请求地址,http:/www.jepson.com/1.php
      <?php
          echo "1;";
       ?>
在 peter.com/1.html 里面,通过 script标签进行请求
    <script type="text/javascript" src="http://www.jepson.com/1.php"></script>

打开F12,进入 network,找到 1.php的那个请求,选中 Response,发现结果是 1,跨域请求就这么成功了! 没错原理就是这么简单。

但是有没有发现,我们是无法获得这个请求到的数据的,怎么办?

script标签默认是同步加载的,那我们就 echo ‘var a = 1;’ ,获取过来就是‘var a = 1;’, 那是不是就是可以认为声明了一个变量并赋值了?

又因为是同步的,所以后面的 script语句是不是就可以用这个 a 了?我们来试一试
- 测试2:

目标请求地址,http:/www.jepson.com/2.php,就一行
    <?php
        echo "var a = 1;";
     ?>

在 peter.com/2.html 里面,通过 script标签进行请求

    <!--  我是不是可以理解为这里声明了一个变量? var a = 1; -->
    <script type="text/javascript" src="http://www.jepson.com/2.php"></script> <script type="text/javascript"> console.log( a ); // 1 </script>

F12 打开控制台,没有错!你输出 a 了, 输出的值为 1,我们拿到了后台传输的数据

但是,这种静态的方式明显有很多弊端,首先要放在代码的顶部,不然下面的没法用到返回的数据

其次,这种静态的方式传参配置很不方便,于是乎我们一般采用 动态创建 script标签的方式,添加到头部,并配参数

JSONP基本原理 - 动态方法创建

动态创建 script标签的方式,添加到头部,并配参数,可以解决金泰
- 测试3:

目标请求地址,http:/www.jepson.com/3.php,就一行
    <?php
        echo "var a = 1;";
     ?>
在 peter.com/3.html 里面,通过 script语句动态创建 script标签进行请求
       <script type="text/javascript">
           var script = document.createElement('script');
           script.src = 'http://www.jepson.com/3.php';
           var head = document.getElementsByTagName('head')[0];
           head.appendChild(script);
           console.log( a );
       </script>

打开 F12,令人震惊的事情发生了,** 居然报错了,**Uncaught ReferenceError: a is not defined(…) ?? a变量没有 定义?

我们打开 network,找到 1.php这个请求,点开response,发现有 ‘var a = 1;’,请求成功了呀?这是什么情况?

注意注意:原来动态创建 script 的方式发送请求 是异步的,虽然请求成功了,但是在使用变量时,请求还没有完成,相当于还没有定义变量,然后就报错了。

那怎么办?这里有一个小技巧, 我们可以 echo ‘foo( 123 )’; 这样相当于请求完毕执行 foo(123),即调用我们 代码中foo函数,我们在代码中写一个函数 function foo( data ) { console.log( data ); } 这就相当于进行了回调,我们拿到了数据。下面是代码演示。

  • 测试4:

    目标请求地址,http:/www.jepson.com/4.php

        <?php
            echo 'foo(123)';
         ?>

    在 peter.com/4.html 里面,通过 script语句动态创建 script标签进行请求

        <script type="text/javascript">
            var script = document.createElement('script');
            script.src = 'http://www.jepson.com/4.php';
            var head = document.getElementsByTagName('head')[0];
            head.appendChild(script);
    
            function foo(data){
                console.log( data );    //foo(123) 对 foo 调用 输出 123
            }
        </script>

    F12 可以看到 输出 123 了, 并且在network中查看请求,response 可以看到是 foo(123)

    那我们就可以用这种动态的方式 很轻松的 拿到后台数据了,只不过前台声明的和 后台 调用的 函数名 需要一样才行,如上面的 foo,这样就不太好了,每次改动,那都要对接一下。

    所以我们可以把回调函数名放在参数中传输。案例如下:

  • 测试5:

    目标请求地址,http:/www.jepson.com/5.php

        <?php
            $cb = $_GET[ 'callback' ];    // get 通过 callback键 得到 函数名
            $arr = array( 'username' => 'zhangsan', 'password' => '123456' );// 我们也可以传复杂一点的数据
            echo $cb.'('. json_encode($arr) .');';// hello( json_encode($arr) )
        ?>

    在 peter.com/5.html 里面,通过 script语句动态创建 script标签进行请求

        <script type="text/javascript">
            function hello(data){
                console.log(data);// Object {username: "zhangsan", password: "123456"}
                console.log(data.username); // zhangsan
                console.log(data.password); // 123456
            }
            var script = document.createElement('script');
            script.src = 'http://jepson.com/5.php?callback=hello';
            var head = document.getElementsByTagName('head')[0];
            head.appendChild(script);
        </script>

**总结:**jsonp的本质:动态创建script标签,然后通过它的src属性发送跨域请求,然后服务器端响应的数据格式为【函数调用】,所以在发送请求之前必须先声明一个函数,并且函数的名字与参数中传递的名字要一致。这里声明的函数是由服务器响应的内容(实际就是一段函数调用js代码)来调用。JSONP是一个协议。

简单封装

上面就是 JSONP 的全部原理了,下面是 学习中实现的 jquery ajax JSONP 方式的 简单封装,感兴趣的可以参考一下。

    function ajax( obj ){
        // 默认参数 由于 jsonp 原理是 在 url体 中传递,
        // 所以仅支持 get, 所以不对 type 进行配置
        var defaults = {
            url : '#',
            dataType : 'jsonp',
            jsonp : 'callback',
            data : {},
            success : function( data ) { console.log( data ) }
        }

        // 处理形参,传递函数的时候就覆盖默认参数,不传递就使用默认的参数
        for ( var key in obj ) {
            defaults[ key ] = obj[ key ];
        }

        // 这里是默认的回调函数名称,根据当前日期和随机数生成
        var cbName = 'jQuery' + ('1.11.1' + Math.random()).replace(/\D/g,"") + '_' + (new Date().getTime());// 去掉所有的小点,相当于 jquery 后面加一串数字_再加上时间数字
        if( defaults.jsonpCallback ){
            cbName = defaults.jsonpCallback;
        }

        // 这里就是回调函数,调用方式:服务器响应内容来调用
        // 向window对象中添加了一个方法,方法名称是变量cbName的值
        window[ cbName ] = function( data ){
            defaults.success( data );//这里success的data是实参
        }

        // 将所传参数 data 进行处理,添加到 src url中
        var param = '';
        for( var attr in defaults.data ){
            param += attr + '=' + defaults.data[ attr ] + '&';
        }
        if( param ){  // 去掉最后的一个 &
            param = param.substring( 0, param.length-1 );
            param = '&' + param;
        }

        // 动态添加 script 标签, 配置参数
        var script = document.createElement( 'script' );
        // defaults.jsonp 后台 get 变量名,cbName 回调函数名, param 变量
        script.src = defaults.url + '?' + defaults.jsonp + '=' + cbName + param; 
        var head = document.getElementsByTagName( 'head' )[ 0 ];
        head.appendChild( script );
    }

解决Ajax 跨域问题 - JSONP原理解析

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
一、介绍 最近跨域问题比较多,而且自己刚好也看到这一块,就总结了一下,关于JSONP的东西百度的话
js跨域,比如说你点击你本地环境里面的一张页面上的一个按钮,请求服务器端的一个文件。要想成功返
之前一直对jsonp跨域问题不知道怎么去解答,今天在百度文库看到了一篇文档,很不错,来一个:传送门
因WEB安全原因,Ajax默认情况下是不能进行跨域请求的,遇到这种问题,自然难不倒可以改变世界的程序
一:故事背景 以前在写WebApi2的时候,一直是用作前后端分离(WebApi2 +angularjs),可是最近自己
//第一种方法使用jsonp的方式 <script type="text/javascript" src="http://www.youxiaju.com/js
一、介绍 CROS是现在主流解决跨域问题的方案,未来估计也是趋势。 1. 跨域资源共享(CORS) Cross-O
客服端: 在A项目下面 建立一个 JsonpClient.aspx页面,代码如下: <%@ Page Language="C#" Auto
一直对jQuery 的jsonp 调用比较疑惑,今天研究了一下jsonp 做了一个简单的调用例子,我用asp做服务端
一直对jQuery 的jsonp 调用比较疑惑,今天研究了一下jsonp 做了一个简单的调用例子,我用asp做服务端
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号