全国统一服务热线:400-633-9193

JS实现的ajax和同源策略(实例讲解二)

    网络     2017-12-14    1315



实例(用户名是否已被注册)

7.1 功能介绍

在注册表单中,当用户填写了用户名后,把光标移开后,会自动向服务器发送异步请求。服务器返回true或false,返回true表示这个用户名已经被注册过,返回false表示没有注册过。

客户端得到服务器返回的结果后,确定是否在用户名文本框后显示“用户名已被注册”的错误信息!

7.2 案例分析

页面中给出注册表单;

在username表单字段中添加onblur事件,调用send()方法;

send()方法获取username表单字段的内容,向服务器发送异步请求,参数为username;

django 的视图函数:获取username参数,判断是否为“yuan”,如果是响应true,否则响应false

参考代码:

?

三、同源策略与jsonp

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
jsonp(jsonpadding)

之前发ajax的时候都是在自己给自己的当前的项目下发

现在我们来实现跨域发。给别人的项目发数据,

创建两个项目,先来测试一下

项目一:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<body>

<h1>项目一</h1>

<button class="send_jsonp">jsonp</button>

<script>

  $(".send_jsonp").click(function () {

    $.ajax({

      url:"http://127.0.0.1:8080/ajax_send2/",  #去请求项目二中的url

      success:function (data) {

        console.log(data)

      }

    })

  })

</script>

</body>

项目二:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

=========================index.html===============

<h1>项目二</h1>

<button class="send_jsonp">jsonp</button>

<script>

  $(".send_jsonp").click(function () {

    $.ajax({

      url:"/ajax_send2/",

      success:function (data) {

        console.log(data)

      }

    })

  })

</script>

</body>

=========================views===============

from django.shortcuts import render,HttpResponse

# Create your views here.

def index(request):

  return render(request, "index.html")

def ajax_send2(request):

  print(222222)

  return HttpResponse("hello")

出现了一个错误,这是因为同源策略给限制了,这是游览器给我们报的一个错

(但是注意,项目2中的访问已经发生了,说明是浏览器对非同源请求返回的结果做了拦截。)

注意:a标签,form,img标签,引用cdn的css等也属于跨域(跨不同的域拿过来文件来使用),不是所有的请求都给做跨域,(为什么要进行跨域呢?因为我想用人家的数据,所以得去别人的url中去拿,借助script标签)

如果用script请求的时候也会报错,当你你返回的数据是一个return Httpresponse(“项目二”)只是一个名字而已,js中如果有一个变量没有声明,就会报错。就像下面的这样了

1

2

3

<script src="http://127.0.0.1:8080/ajax_send2/">

  项目二

</script>

只有发ajax的时候给拦截了,所以要解决的问题只是针对ajax请求能够实现跨域请求

解决同源策源的两个方法:

1、jsonp(将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。)

jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。

思考:这算怎么回事?

1

<script src="http://code.jquery.com/jquery-latest.js"></script>

借助script标签,实现跨域请求,示例:

所以只是单纯的返回一个也没有什么意义,我们需要的是数据

如下:可以返回一个字典,不过也可以返回其他的(简单的解决了跨域,利用script)

项目一:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<body>

<h1>项目一</h1>

<button class="send_jsonp">jsonp</button>

<script>

  $(".send_jsonp").click(function () {

    $.ajax({

      url:"",

      success:function (data) {

        console.log(data)

      }

    })

  });

  function func(arg) {

    console.log(arg)

  }

</script>

<script src="http://127.0.0.1:8080/ajax_send2/"></script>

</body>

项目二:

1

2

3

4

5

6

7

8

def ajax_send2(request):

  import json

  print(222222)

  # return HttpResponse("func('name')")

  s = {"name":"haiyan","age":12}

  # return HttpResponse("func('name')")

  return HttpResponse("func('%s')"%json.dumps(s))  #返回一个func()字符串,正好自己的ajax里面有个func函数,就去执行func函数了,

                                arg就是传的形参

这样就会取到值了

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

但是以上的方式也有不足,回调函数的名字和返回的那个名字的一致。并且一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。

解决办法:javascript动态的创建script标签

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

===========================jQuery实现=====================

{#  创建一个script标签,让他请求一次,请求完了删除他#}

  //动态生成一个script标签,直接可以定义个函数,放在函数里面

  function add_script(url) {

    var ele_script = $("<script>");

    ele_script.attr("src",url);

    ele_script.attr("id","script");

    $("body").append(ele_script);

    $("#script").remove()

  }

  $(".kuayu").click(function () {

    add_script("http://127.0.0.1:8080/ajax_send2/")

  });

</script>

==================js实现==========================

<button onclick="f()">sendAjax</button>

<script>

  function addScriptTag(src){

     var script = document.createElement('script');

     script.setAttribute("type","text/javascript");

     script.src = src;

     document.body.appendChild(script);

     document.body.removeChild(script);

  }

  function func(name){

    alert("hello"+name)

  }

  function f(){

     addScriptTag("http://127.0.0.1:7766/SendAjax/")

  }

</script>

为了更加灵活,现在将你自己在客户端定义的回调函数的函数名传送给服务端,服务端则会返回以你定义的回调函数名的方法,将获取的json数据传入这个方法完成回调:

1

2

3

function f(){

     addScriptTag("http://127.0.0.1:7766/SendAjax/?callbacks=func")

  }

将视图views改为

四、jQuery对JSONP的实现

getJSON

jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法

1

2

3

4

5

6

7

8

9

10

11

<button onclick="f()">sendAjax</button>

<script>

  function f(){

     $.getJSON("http://127.0.0.1:7766/SendAjax/?callbacks=?",function(arg){

      alert("hello"+arg)

    }); 匿名函数

  }

</script>

8002的views不改动。

结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个?是内部自动生成的一个回调函数名。

此外,如果说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现

$.ajax

1

2

3

4

5

6

7

8

<script>

  function f(){

     $.ajax({

        url:"http://127.0.0.1:7766/SendAjax/",

        dataType:"jsonp", 

        jsonp: 'callbacks',  #键

          jsonpCallback:"SayHi" #函数的名字

 }); } function SayHi(arg){ alert(arg); } </script>

8002的views不改动。

当然,最简单的形式还是通过回调函数来处理:

1

2

3

4

5

6

7

8

9

10

11

12

13

<script>

  function f(){

      $.ajax({

        url:"http://127.0.0.1:7766/SendAjax/",

        dataType:"jsonp",      //必须有,告诉server,这次访问要的是一个jsonp的结果。

        jsonp: 'callbacks',     //jQuery帮助随机生成的:callbacks="wner"

        success:function(data){

          alert("hi "+data)

       }

     });

    }

</script>

jsonp: 'callbacks'就是定义一个存放回调函数的键,jsonpCallback是前端定义好的回调函数方法名'SayHi',server端接受callback键对应值后就可以在其中填充数据打包返回了;

jsonpCallback参数可以不定义,jquery会自动定义一个随机名发过去,那前端就得用回调函数来处理对应数据了。利用jQuery可以很方便的实现JSONP来进行跨域访问。  

注意 JSONP一定是GET请求

五、应用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

// 跨域请求实例

  $(".jiangxiTV").click(function () {

    $.ajax({

      url:"http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403",

       dataType: 'jsonp',

       jsonp: 'callback',

       jsonpCallback: 'list',

       success:function (data) {

         console.log(data.data);  // [{},{},{},{},{},{}]

         week_list=data.data;

         $.each(week_list,function (i,j) {

           console.log(i,j); // 1 {week: "周一", list: Array(19)}

           s="<p>"+j.week+"列表</p>";

           $(".show_list").append(s);

           $.each(j.list,function (k,v) { // {time: "0030", name: "通宵剧场六集连播", link: "http://www.jxntv.cn/live/jxtv2.shtml"}

             a="<p><a href='"+v.link+"'>"+v.name+"</a></p>";

             $(".show_list").append(a);

           })

         })

       }

    })

  })



  分享到:  
0.2409s