Ajax跨域(二)jsonp实现跨域

本文总结自极客学院跨域Ajax实现视频教程地址

一、jsonp实现跨域原理

1.本质并不是ajax,只是执行了跨域javascript脚本
2.html中,所有带有“src”属性的标签都可以跨域(如:img、script),它们的src都可以指向另一个域的资源,浏览器也可以把另一个域的资源加载进来。所以,可以通过<script>标签加载一段其他域的<script>标签或者一段可执行的动态脚本,这个脚本课携带另一个域的数据到本域中进行相应的处理。

二、jsonp实现方法

1.直接加载<script>

在请求域页面,写一个<script>,它的src指向另一个域(这里假设请求域为:a.test.com,另一个域为:b.test.com)
写一个html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp</title>
    <script src="js/jquery-1.11.3.js"></script>
</head>
<body>
    <script>
        function callback(data) {
            console.log(data);
        }
    </script>
    <script src="http://b.test.com:3000/testjsonp"></script>    
</body>
</html>
  • 在需要跨域的页面,写一个<script>标签,src指向另一个域,指向的那个域应该提供一个动态的<script>脚本
  • /testjsonp返回的数据类型一定是一个<script>脚本,同时,这个脚本中包含了数据信息
  • 脚本加载完,相当于执行了一个callback函数:callback({one: 1,two: 2});
  • 因此在调用之前,应该先定义一个callback函数,可以接收后台返回的数据,它的方法体为具体的数据处理逻辑

  • 因为<script>是直接写在页面中的,所以在页面加载时,<script>标签的内容就被执行了

后台代码(node)
/**
 * Created by lenovo on 2016/8/4.
 */
var express = require('express');
var router = express.Router();

router.all('/',function(req,res) {
    res.sendFile('./public/index.html');
});

router.all('/testjsonp',function(req,res) {
    res.setHeader('Content-Type','application/javascript');    //设置返回的类型是script类型
    res.send('callback(' + JSON.stringify({one: 1,two: 2}) + ')');   //返回的是一段文本,这个文本是一段javascript代码。代码被调用后,实际上是执行了一个callback函数,参数为一个json对象的字面值{one: 1,two: 2}
});

module.exports = router;

这里写图片描述

2.封装jsonp

一般都是点击某个按钮或者在特定的操作之后,再动态生成一段script,加载另一个域的脚本,然后作为数据处理。在处理完之后,将script标签从页面中移出。而不是直接将script便签写在页面中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp2</title>
    <link rel="stylesheet" href="css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/main.css" />
    <script src="js/jquery-1.11.3.js"></script>
</head>
<body>
     <div class="container">
         <div class="row">
             <div class="col-md-12">
                 <p>动态生成javascript</p>
                 <button class="btn btn-primary" onclick="calltest()">调用测试</button>
             </div>
         </div>
     </div>

    <script>
        //封装一个jsonp方法,当我们需要跨域请求的时候,只需要调用这个方法即可
        function jsonp(url, data, callback) {   
            var script = document.createElement('script');
            document.body.appendChild(script);
            data = data || {};
            data.callback = 'cb' + new Date().getTime();    
            window[data.callback] = callback;     

            script.src = url;     //当执行这行代码时,script标签就知道它的执行目标在哪里,这时,浏览器就会发起一次网络请求,到我们指定的位置去加载动态脚本,实际上就是加载数据
            script.onload = function () {    //标签加载完之后的事件
                document.body.removeChild(script);   
                 //script标签加载完成后,意味着脚本被执行完成了,此时,将脚本从页面中移出掉
            }
        }
        function calltest() {
            jsonp('http://b.test.com:3000/testjsonp2',{test: 'ok'},function(data) {
                console.log(data);
            });
        }

    </script>
</body>
</html>

关键点:
1.如何动态的生成和移出script便签
2.如何正确的绑定回调函数,在其调用的时候能够正确的返回

  • 不管用户传入的data是什么,最终我们都需要自己加一个参数,来告诉后台回调函数的名称;
  • 前台传入的回调函数callback是一个匿名函数,但后台调用必须知道回调函数的名称,所以用’cb’ + new Date().getTime(); 给callback起一个随机的名字;
  • 把随机的名称作为window的属性存储起来,同时让它指向callback。这样就相当于把匿名函数加载到了全局的空间里,这样我们可以在任意位置,以这个随机名称来调用这个随机函数
  • url用来设置script的src(假设url是不带参数的,直击在后面加上?并跟上数据)。用jquery的param来完成参数的序列化
  • 当脚本被执行之后,浏览器自动返回被执行的结果,实际上也就是间接调用了callback
后台代码
/**
 * Created by lenovo on 2016/8/4.
 */
var express = require('express');
var router = express.Router();

router.all('/',function(req,res) {
    res.sendFile('./public/index.html');
});
router.all('/testjsonp2',function(req,res) {
    res.setHeader('Content-Type','application/javascript');
    res.send(req.query.callback + '(' + JSON.stringify({one: 1,two: 2}) + ')');    
    //后台代码在返回时必须知道回调函数的名称,才能正确的调用;此处调用callback函数的别名来执行它
    //拼接成一行可执行的脚本代码
    //第一个是回调函数名,它是在请求时通过参数传入的
});
});

module.exports = router;

执行结果
这里写图片描述

此处的回调函数名为随机生成的名称callback=

3.jquery中JSONP方法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp2</title>
    <link rel="stylesheet" href="css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/main.css" />
    <script src="js/jquery-1.11.3.js"></script>
</head>
<body>
     <div class="container">
         <div class="row">
             <div class="col-md-12">
                 <p>JQuery对jsonp的支持</p>
                 <button class="btn btn-primary" onclick="getJson()">test GetJson</button>  
             </div>
         </div>
     </div>

    <script>
        function getJson() {    
            $.getJSON('http://b.test.com:3000/testjsonp2?callback=?',{   
                dataType: 'jsonp'
            }).done(function(data) {
                console.log(data);
            })
        }
    </script>
</body>
</html>
  • JSONP是jquery底层$.ajax()方法的一个简化形式
  • 请求地址后面必须加上callback=?的参数,callback为回调函数名。只有以这样的形式定义url,才会认为是以jsonp的请求方式发起的ajax请求,若后面没有加上该参数,会被认为是普通的同域的ajax请求。
  • jsonp会生成一个随机的函数名,来绑定到传入的回调函数上(回调函数名被jquery自动替换,后面仔添加了一个时间戳,来避免缓存)

!后台代码与前面的一样

4.jquery的底层$.ajax()方法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp2</title>
    <link rel="stylesheet" href="css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/main.css" />
    <script src="js/jquery-1.11.3.js"></script>
</head>
<body>
     <div class="container">
         <div class="row">
             <div class="col-md-12">
                 <p>ajax 返回指定jsonp类型</p>
                 <button class="btn btn-primary" onclick="ajaxJsonp()">test GetJson</button>
             </div>
         </div>
     </div>

    <script>
        function ajaxJsonp() {
            $.ajax('http://b.test.com:3000/testjsonp2?callback=?',{
                dataType: 'jsonp'    //指定返回的数据类型为jsonp,这样ajax就会以jsonp的方式发起请求
            }).done(function(data) {    //请求完成过的回调函数,成功或失败
                console.log(data);
            });
        }
    </script>
</body>
</html>

$.ajax()的请求参数与JSONP()一样

5.jquery的ajax方法(不指定回调参数)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp2</title>
    <link rel="stylesheet" href="css/bootstrap.min.css" />
    <link rel="stylesheet" href="css/main.css" />
    <script src="js/jquery-1.11.3.js"></script>
</head>
<body>
     <div class="container">
         <div class="row">
             <div class="col-md-12">
                 <p>jsonpcallback 参数</p>
                 <button class="btn btn-primary" onclick="jsonpParams()">test GetJson</button>
             </div>
         </div>
     </div>

    <script>
        function jsonpParams() {
            $.ajax('http://b.test.com:3000/testjsonp3',{
                dataType: 'jsonp',     
                jsonp: 'cbname',       
                jsonpCallback: 'cbfun',
                cache: true,
                success: function(data) {
                    console.log(data);
                }
            })
        }
    </script>
</body>
</html>

关键点在于两个参数的设置:jsonp和jsonpCallback。
它们的作用是起到可以把请求参数后面携带的’ ?callback=? ’ 替换掉的作用
jsonp:相当于参数中的 callback,此处指定cbname作为参数的名称
jsonpCallback:用来指定具体的参数名称的值,来替换随机的参数名

执行结果:
这里写图片描述

此时,回调哈数名称由原来的随机函数名变成了设定的 cbname=cbfun

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值