zoukankan      html  css  js  c++  java
  • JS的Ajax和同源策略

    JS实现的ajax

    AJAX核心(XMLHttpRequest

    其实AJAX就是在Javascript中多添加了一个对象:XMLHttpRequest对象。所有的异步交互都是使用XMLHttpServlet对象完成的。也就是说,我们只需要学习一个Javascript的新对象即可。

    var xmlHttp = new XMLHttpRequest();(大多数浏览器都支持DOM2规范)

    注意,各个浏览器对XMLHttpRequest的支持也是不同的!为了处理浏览器兼容问题,给出下面方法来创建XMLHttpRequest对象:

    function createXMLHttpRequest() {
            var xmlHttp;
            // 适用于大多数浏览器,以及IE7和IE更高版本
            try{
                xmlHttp = new XMLHttpRequest();
            } catch (e) {
                // 适用于IE6
                try {
                    xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                    // 适用于IE5.5,以及IE更早版本
                    try{
                        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                    } catch (e){}
                }
            }            
            return xmlHttp;
        }

    使用流程

    步骤1:  打开与服务器的连接(open方法)

    当得到XMLHttpRequest对象后,就可以调用该对象的open()方法打开与服务器的连接了。open()方法的参数如下:

    open(method, url, async)

    • method:请求方式,通常为GETPOST
    • url:请求的服务器地址,例如:/ajaxdemo1/AServlet,若为GET请求,还可以在URL后追加参数;
    • async:这个参数可以不给,默认值为true,表示异步请求;
      var xmlHttp = createXMLHttpRequest();
      xmlHttp.open("GET", "/ajax_get/?a=1", true); 

    步骤2:  发送请求

    当使用open打开连接后,就可以调用XMLHttpRequest对象的send()方法发送请求了。send()方法的参数为POST请求参数,即对应HTTP协议的请求体内容,若是GET请求,需要在URL后连接参数。

    注意:若没有参数,需要给出null为参数!若不给出null为参数,可能会导致FireFox浏览器不能正常发送请求!

    xmlHttp.send(null);

    当请求发送出去后,服务器端就开始执行了,但服务器端的响应还没有接收到。接下来我们来接收服务器的响应。

    XMLHttpRequest对象有一个onreadystatechange事件,它会在XMLHttpRequest对象的状态发生变化时被调用。下面介绍一下XMLHttpRequest对象的5种状态:

    • 0:初始化未完成状态,只是创建了XMLHttpRequest对象,还未调用open()方法;
    • 1:请求已开始,open()方法已调用,但还没调用send()方法;
    • 2:请求发送完成状态,send()方法已调用;
    • 3:开始读取服务器响应;
    • 4:读取服务器响应结束。 

    onreadystatechange事件会在状态为1234时引发。

      下面代码会被执行四次!对应XMLHttpRequest的四种状态!

    xmlHttp.onreadystatechange = function() {
                alert('hello');
            };
    

      但通常我们只关心最后一种状态,即读取服务器响应结束时,客户端才会做出改变。我们可以通过XMLHttpRequest对象的readyState属性来得到XMLHttpRequest对象的状态。

    xmlHttp.onreadystatechange = function() {
                if(xmlHttp.readyState == 4) {
                    alert('hello');    
                }
            };

    其实我们还要关心服务器响应的状态码是否为200,其服务器响应为404,或500,那么就表示请求失败了。我们可以通过XMLHttpRequest对象的status属性得到服务器的状态码。

    最后,我们还需要获取到服务器响应的内容,可以通过XMLHttpRequest对象的responseText得到服务器响应内容。

    xmlHttp.onreadystatechange = function() {
                if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                    alert(xmlHttp.responseText);    
                }
            };

    if 发送POST请求

    <1>需要设置请求头:xmlHttp.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”)注意 :form表单会默认这个键值对不设定,Web服务器会忽略请求体的内容。

    <2>在发送时可以指定请求体了:xmlHttp.send(“username=yuan&password=123”)

    JS实现ajax小结

    /*创建XMLHttpRequest对象;
        调用open()方法打开与服务器的连接;
        调用send()方法发送请求;
        为XMLHttpRequest对象指定onreadystatechange事件函数,这个函数会在
    
        XMLHttpRequest的1、2、3、4,四种状态时被调用;
    
        XMLHttpRequest对象的5种状态,通常我们只关心4状态。
    
        XMLHttpRequest对象的status属性表示服务器状态码,它只有在readyState为4时才能获取到。
    
        XMLHttpRequest对象的responseText属性表示服务器响应内容,它只有在
        readyState为4时才能获取到*/

    同源策略

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

    同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
     
    需要注意的是对于当前页面来说,页面内存放的JS文件的与并不重要,重要的是加载JS页面所在的域是什么.
    a.com通过以下代码:
    <script src="http//b.com/b.js"></script>
    

    加载了b.com上的b.js,但是b.js是运行在a.com中的,因此对于当前打开的页面来说,b.js的源就应该是a.com 而非 b.com.

    在浏览器中<script>,<img>,<iframe>,<link>等标签都可以跨域加载资源,而不受同源策略的限制.这些带src属性的标签每次加载时,实际上是由浏览器发起了一次GET请求,不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制JS的权限,使其不能读写返回的内容(也就是说对于JS的跨域请求返回的结果做了拦截)

    Jsonp

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

    <script>src标签的功能--从src的url里获得内容作为JS代码

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

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

    # =============================http://127.0.0.1:8001/index
    
    
    <button>ajax</button>
    {% csrf_token %}
    
    <script>
        function func(name){
            alert(name)
        }
    </script>
    
    <script src="http://127.0.0.1:7766/SendAjax/"></script> #func('yuan')
    
    
    # =============================http://127.0.0.1:8002/
    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    
    
    def SendAjax(request):
    
        import json
        return HttpResponse("func('yuan')")

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

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

          一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。

    <button onclick="f()">sendAjax</button>
    
    <script>
    # 这个函数接受一个url,并且根据这个url创建一个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数据传入这个方法完成回调:

    将8001的f()改写为:

    function f(){
             addScriptTag("http://127.0.0.1:7766/SendAjax/?callbacks=func")
        }
    

    8002的views改为:

    def SendAjax(request):
     
        import json
     
        dic={"k1":"v1"}
     
        print("callbacks:",request.GET.get("callbacks"))
        callbacks=request.GET.get("callbacks")
     
        return HttpResponse("%s('%s')"%(callbacks,json.dumps(dic)))

    jQuery对JSONP的实现

    getJSON

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

    8001的html改为

    <button onclick="f()">sendAjax</button>
    
    <script>
    
        function f(){
              $.getJSON("http://127.0.0.1:7766/SendAjax/?callbacks=?",function(arg){
                alert("hello"+arg)
            });
        }
        
    </script>

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

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

    $.ajax

    8001的html改为:

    <script>
    
        function f(){
              $.ajax({
                    url:"http://127.0.0.1:7766/SendAjax/",
                    dataType:"jsonp",
                    jsonp: 'callbacks', # 这个是键
                    jsonpCallback:"SayHi" # 回调函数名
               });
    
           }
    
        function SayHi(arg){
                    alert(arg);
                }
    
    </script>
    

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

    <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请求

  • 相关阅读:
    进程池,线程池,协程,gevent模块,协程实现单线程服务端与多线程客户端通信,IO模型
    线程相关 GIL queue event 死锁与递归锁 信号量l
    生产者消费者模型 线程相关
    进程的开启方式 进程的join方法 进程间的内存隔离 其他相关方法 守护进程 互斥锁
    udp协议 及相关 利用tcp上传文件 socketserver服务
    socket套接字 tcp协议下的粘包处理
    常用模块的完善 random shutil shevle 三流 logging
    day 29 元类
    Django入门
    MySQL多表查询
  • 原文地址:https://www.cnblogs.com/wwg945/p/8486208.html
Copyright © 2011-2022 走看看