zoukankan      html  css  js  c++  java
  • 一、Django前后端交互之Ajax和跨域问题

    一、Ajax介绍

    1、概述

    AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。AJAXAsynchronous Javascript And XML)翻译成中文就是异步JavascriptXML”。即:使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,比如还有JSON)。

    • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
    • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

    2、使用场景

    • 搜索引擎(谷歌、百度)在用户输入某个关键字后,会出来一串提示关键字;
    • 注册页面,输入信息后,如果信息有重复或缺失,会自动提示;
    • 当我们只要修改网页上的部分内容时,单独局部刷新就可以做到;

    3、优缺点

    优点:

    • AJAX使用Javascript技术向服务器发送异步请求;
    • AJAX无须刷新整个页面;
    • 因为服务器响应内容不再是整个页面,而是页面中的局部,所以AJAX性能高;

    缺点:

    • AJAX并不适合所有场景,很多时候还是要使用同步交互;
    • AJAX虽然提高了用户体验,但无形中向服务器发送的请求次数增多了,导致服务器压力增大;
    • 因为AJAX是在浏览器中使用Javascript技术完成的,所以还需要处理浏览器兼容性问题,当然,如果使用jQuery的话,则不用考虑这个问题;

    二、通过JavaScript实现Ajax

    1、过程和请求相关

    使用Ajax的过程:

    • 创建核心对象,根据不同浏览器版本新建核心对象(主要原因是浏览器兼容问题);
    • 使用核心对象打开与服务器的连接(open方法);
    • 发送请求(send方法)
    • 注册监听,监听服务器响应。(通过判断核心对象的就绪程度和状态码)

     

    XMLHTTPRequest关键知识点:

    • open(请求方式, URL, 是否异步)
    • send(请求体)
    • onreadystatechange,指定监听函数,它会在xmlHttp对象的状态发生变化时被调用
    • readyState,当前xmlHttp对象的状态,其中4状态表示服务器响应结束
    • status:服务器响应的状态码,只有服务器响应结束时才有这个东东,200表示响应成功;
    • responseText:获取服务器的响应体,文本
    • responseXML:获取服务器的响应体,XML

    2、通过JavaScript实现Ajax之无后台交互

    <html>
    <head>
    <script type="text/javascript">
    function loadXMLDoc()
    {
    var xmlhttp;
    if (window.XMLHttpRequest)
      {// code for IE7+, Firefox, Chrome, Opera, Safari
      xmlhttp=new XMLHttpRequest();
      }
    else
      {// code for IE6, IE5
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
      }
    xmlhttp.onreadystatechange=function()
      {
      if (xmlhttp.readyState==4 && xmlhttp.status==200)
        {
        document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
        }
      }
    xmlhttp.open("GET","/ajax/test1.txt",true);
    xmlhttp.send();
    }
    </script>
    </head>
    <body>
    
    <div id="myDiv"><h2>Let AJAX change this text</h2></div>
    <button type="button" onclick="loadXMLDoc()">通过 AJAX 改变内容</button>
    
    </body>
    </html>
    

      

    3、通过JavaScript实现Ajax之与后台交互

    通过Django实现,其实唯一区别就是在open的时候,把URL修改成Django的一个URL即可,包括GET和POST方法的URL。

    a、urls.py文件

    urlpatterns = [
        url(r'^ajax_get',views.ajax_get),
        url(r'^ajax_post',views.ajax_post)
    ]
    

      

    b、views.py文件

    def ajax_get(req):
        return render(req,'ajax_get.html')
    
    def ajax_post(req):
        if req.method=='POST':
            print req.POST
        else:
            print req.GET
        return HttpResponse('ajax_post')
    

      

    c、ajax_get.html文件

     

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>测试ajax的GET方法</title>
        <script>
            function loadXMLDoc()
                {
                    var xmlhttp;  //定义局部变量xmlhttp
                    if (window.XMLHttpRequest) //XMLHttpRequet对象用于和服务器交互数据。
                        {
                            // IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
                            xmlhttp=new XMLHttpRequest();
                        }
                    else{
                            // IE6, IE5 浏览器执行代码
                            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
                        }
                    //侦听
                    xmlhttp.onreadystatechange=function(){
                            if (xmlhttp.readyState==4 && xmlhttp.status==200){
                                document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
                            }
                        }
                    //POST方法
                     xmlhttp.open("POST","./ajax_post",true);
                    //GET方法
                      //xmlhttp.open("GET","./user_info",true);
                    //设置头部信息
                    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                    //POST method发送
                    xmlhttp.send("name=xuequn");
                    //GET method发送
                    //xmlhttp.send();
                }
    </script>
    </head>
    <body>
         <div id="myDiv"><h2>使用 AJAX 修改该文本内容</h2></div>
        <button type="button" onclick="loadXMLDoc()">修改</button>
    </body>
    </html>
    

      

      

     d、测试结果

    GET方法:

     

     

     

    POST方法:

     

    三、通过jQuery实现Ajax

     1、两个快捷API

    <1>$.get(url, [data], [callback], [type])
    <2>$.post(url, [data], [callback], [type])  
    url:请求的URL
    data:发送的数据
    callback:回调函数,前端发送数据给后端之后,后端返回数据给前端,前端接受到的数据
    type:text|html|json|script
    

      

     2、两个不常用API

    getJSON(url,data,callback)

    <html>
    <head>
    <script type="text/javascript" src="/jquery/jquery.js"></script>
    <script type="text/javascript">
    $(document).ready(function(){
      $("button").click(function(){
        $.getJSON("/example/jquery/demo_ajax_json.js",function(result){
          $.each(result, function(i, field){
            $("p").append(field + " ");
          });
        });
      });
    });
    </script>
    </head>
    
    <body>
    
    <button>获得 JSON 数据</button>
    <p></p>
    
    </body>
    </html>
    
    
    ///example/jquery/demo_ajax_json.js
    { 
      "firstName": "Bill",
      "lastName": "Gates",
      "age": 60
    }
    

      

    getScript( url ,callback ])

    jQuery.getScript("http://dev.jquery.com/view/trunk/plugins/color/jquery.color.js",
     function(){
      $("#go").click(function(){
        $(".block").animate( { backgroundColor: 'pink' }, 1000)
          .animate( { backgroundColor: 'blue' }, 1000);
      });
    });
    

      

    3、最常用的方法

    $.ajax()

    $(function(){
        $('#send').click(function(){
             $.ajax({
                 type: "GET",
                 url: "test.json",
                 data: {username:$("#username").val(), content:$("#content").val()},
                 dataType: "json",
                 success: function(data){
                             $('#resText').empty();   //清空resText里面的所有内容
                             var html = ''; 
                             $.each(data, function(commentIndex, comment){
                                   html += '<div class="comment"><h6>' + comment['username']
                                             + ':</h6><p class="para"' + comment['content']
                                             + '</p></div>';
                             });
                             $('#resText').html(html);
                          }
             });
        });
    });
    

      

    ajax的参数

    1.url: 
    要求为String类型的参数,(默认为当前页地址)发送请求的地址。
    
    2.type: 
    要求为String类型的参数,请求方式(post或get)默认为get。注意其他http请求方法,例如put和delete也可以使用,但仅部分浏览器支持。
    
    3.timeout: 
    要求为Number类型的参数,设置请求超时时间(毫秒)。此设置将覆盖$.ajaxSetup()方法的全局设置。
    
    4.async: 
    要求为Boolean类型的参数,默认设置为true,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为false。注意,同步请求将锁住浏览器,用户其他操作必须等待请求完成才可以执行。
    
    5.cache: 
    要求为Boolean类型的参数,默认为true(当dataType为script时,默认为false),设置为false将不会从浏览器缓存中加载请求信息。
    
    6.data: 
    要求为Object或String类型的参数,发送到服务器的数据。如果已经不是字符串,将自动转换为字符串格式。get请求中将附加在url后。防止这种自动转换,可以查看processData选项。
    对象必须为key/value格式,例如{foo1:"bar1",foo2:"bar2"}转换为&foo1=bar1&foo2=bar2。如果是数组,JQuery将自动为不同值对应同一个名称。例如{foo:["bar1","bar2"]}转换为&foo=bar1&foo=bar2。
    
    7.dataType: 
    要求为String类型的参数,预期服务器返回的数据类型。如果不指定,JQuery将自动根据http包mime信息返回responseXML或responseText,并作为回调函数参数传递。可用的类型如下:
    xml:返回XML文档,可用JQuery处理。
    html:返回纯文本HTML信息;包含的script标签会在插入DOM时执行。
    script:返回纯文本JavaScript代码。不会自动缓存结果。除非设置了cache参数。注意在远程请求时(不在同一个域下),所有post请求都将转为get请求。
    json:返回JSON数据。
    jsonp:JSONP格式。使用SONP形式调用函数时,例如myurl?callback=?,JQuery将自动替换后一个“?”为正确的函数名,以执行回调函数。
    text:返回纯文本字符串。
    
    8.beforeSend:
    要求为Function类型的参数,发送请求前可以修改XMLHttpRequest对象的函数,例如添加自定义HTTP头。在beforeSend中如果返回false可以取消本次ajax请求。XMLHttpRequest对象是惟一的参数。
                function(XMLHttpRequest){
                   this;   //调用本次ajax请求时传递的options参数
                }
    9.complete:
    要求为Function类型的参数,请求完成后调用的回调函数(请求成功或失败时均调用)。参数:XMLHttpRequest对象和一个描述成功请求类型的字符串。
              function(XMLHttpRequest, textStatus){
                 this;    //调用本次ajax请求时传递的options参数
              }
    
    10.success:要求为Function类型的参数,请求成功后调用的回调函数,有两个参数。
             (1)由服务器返回,并根据dataType参数进行处理后的数据。
             (2)描述状态的字符串。
             function(data, textStatus){
                //data可能是xmlDoc、jsonObj、html、text等等
                this;  //调用本次ajax请求时传递的options参数
             }
    
    11.error:
    要求为Function类型的参数,请求失败时被调用的函数。该函数有3个参数,即XMLHttpRequest对象、错误信息、捕获的错误对象(可选)。ajax事件函数如下:
           function(XMLHttpRequest, textStatus, errorThrown){
              //通常情况下textStatus和errorThrown只有其中一个包含信息
              this;   //调用本次ajax请求时传递的options参数
           }
    
    12.contentType:
    要求为String类型的参数,当发送信息至服务器时,内容编码类型默认为"application/x-www-form-urlencoded"。该默认值适合大多数应用场合。
    
    13.dataFilter:
    要求为Function类型的参数,给Ajax返回的原始数据进行预处理的函数。提供data和type两个参数。data是Ajax返回的原始数据,
    type是调用jQuery.ajax时提供的dataType参数。函数返回的值将由jQuery进一步处理。
                function(data, type){
                    //返回处理后的数据
                    return data;
                }
    
    14.dataFilter:
    要求为Function类型的参数,给Ajax返回的原始数据进行预处理的函数。提供data和type两个参数。data是Ajax返回的原始数据,
    type是调用jQuery.ajax时提供的dataType参数。函数返回的值将由jQuery进一步处理。
                function(data, type){
                    //返回处理后的数据
                    return data;
                }
    
    15.global:
    要求为Boolean类型的参数,默认为true。表示是否触发全局ajax事件。设置为false将不会触发全局ajax事件,ajaxStart或ajaxStop可用于控制各种ajax事件。
    
    16.ifModified:
    要求为Boolean类型的参数,默认为false。仅在服务器数据改变时获取新数据。服务器数据改变判断的依据是Last-Modified头信息。默认值是false,即忽略头信息。
    
    17.jsonp:
    要求为String类型的参数,在一个jsonp请求中重写回调函数的名字。该值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,
    例如{jsonp:'onJsonPLoad'}会导致将"onJsonPLoad=?"传给服务器。
    
    18.username:
    要求为String类型的参数,用于响应HTTP访问认证请求的用户名。
    
    19.password:
    要求为String类型的参数,用于响应HTTP访问认证请求的密码。
    
    20.processData:
    要求为Boolean类型的参数,默认为true。默认情况下,发送的数据将被转换为对象(从技术角度来讲并非字符串)以配合默认内容类型"application/x-www-form-urlencoded"。
    如果要发送DOM树信息或者其他不希望转换的信息,请设置为false。
    
    21.scriptCharset:
    要求为String类型的参数,只有当请求时dataType为"jsonp"或者"script",并且type是GET时才会用于强制修改字符集(charset)。通常在本地和远程的内容编码不同时使用。
    

      

      

    4、Django中设定状态码

    HttpResponse.status_code = 400 //手动设定返回的状态码为400


    四、跨域问题

    4.1 同源策略机制

          浏览器有一个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指,域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况下,不能读写对方的资源。

    简单的来说,浏览器允许包含在页面A的脚本访问第二个页面B的数据资源,这一切是建立在A和B页面是同源的基础上。

    如果Web世界没有同源策略,当你登录淘宝账号并打开另一个站点时,这个站点上的JavaScript可以跨域读取你的任意账号的数据,这样整个Web世界就无隐私可言了。

     

     

    4.2 问题出现

     在同源策略下,比如我在URL01:http://localhost/user_manager/test_jsonp/上获取https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse的数据时,就是属于跨域了,此时会出现问题:

    
    

    代码如下:重点在open里面的URL,是属于跨域的行为。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>ajax</title>
    </head>
    <body>
        <div id="mydiv">
            <button id="btn">点击</button>
        </div>
    </body>
    <script type="text/javascript">
        window.onload = function() {
    
        var oBtn = document.getElementById('btn');
    
        oBtn.onclick = function() {
    
            var xhr = new XMLHttpRequest();
    
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                        alert( xhr.responseText );
                }
            };
    
            xhr.open('get', 'https://api.douban.com/v2/book/search?q=javascript&count=1', true);
            xhr.send(); 
        };
    
    };
    </script>
    </html>
    

      上述程序运行时会报错:

     

    4.3 JSONP介绍

    JSONP 是 JSON with padding(填充式 JSON 或参数式 JSON)的简写。

    JSONP实现跨域请求的原理简单的说,就是动态创建<script>标签,然后利用<script>的src 不受同源策略约束来跨域获取数据。

    JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。

     

    其实网上关于JSONP的讲解有很多,大概总结如下:

    1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;

    2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>);

    3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;

    4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;

    5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。

    6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

    7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

    如果对于callback参数如何使用还有些模糊的话,我们后面会有具体的实例来讲解。

     

    4.4 JavaScript实现跨域

    1、我们知道,哪怕跨域js文件中的代码(当然指符合web脚本安全策略的),web页面也是可以无条件执行的,比如img中的src指定的图片地址可以是网上任意图片。

    远程服务器remoteserver.com根目录下有个remote.js文件代码如下:

    alert('我是远程文件');
    本地服务器localserver.com下有个jsonp.html页面代码如下:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
    </head>
    <body>
    
    </body>
    </html>
    复制代码
    

      

    毫无疑问,页面将会弹出一个提示窗体,显示跨域调用成功。

     

    2、现在我们在jsonp.html页面定义一个函数,然后在远程remote.js中传入数据进行调用。

    jsonp.html页面代码如下:

     

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script type="text/javascript">
        var localHandler = function(data){
            alert('我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:' + data.result);
        };
        </script>
        <script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
    </head>
    <body>
    
    </body>
    </html>
    

      remote.js文件代码如下:

    localHandler({"result":"我是远程js带来的数据"});
    

      运行之后查看结果,页面成功弹出提示窗口,显示本地函数被跨域的远程js调用成功,并且还接收到了远程js带来的数据。很欣喜,跨域远程获取数据的目的基本实现了,但是又一个问题出现了,我怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?我们接着往下看。

    3、聪明的开发者很容易想到,只要服务端提供的js脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端“我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来生成js脚本并响应了。

    这里其实就是跨域的api接口。

    看jsonp.html页面的代码:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script type="text/javascript">
        // 得到航班信息查询结果后的回调函数
        var handleResponse = function(data){
            alert(data.total);
        };
        // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
        var url = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
        // 创建script标签,设置其属性
        var script = document.createElement('script');
        script.setAttribute('src', url);
        // 把script标签加入head,此时调用开始
        document.getElementsByTagName('head')[0].appendChild(script);
        </script>
    </head>
    <body>
    
    </body>
    </html>
    

      这里的API接口是豆瓣的一个获取图书信息的接口,本质就是在指定位置添加了一个script标签,且是通过src方式,然后通过callback参数获取返回值,返回值可以直接使用,这样就做到了跨域。

    4.5  jQuery实现跨域

    jQuery实现起来会更加简单,因为它已经帮你包装了一层,比如:指定url、数据类型,最重要的是,jQuery里面,直接可以通过success参数调用获取的结果,当然,也可以使用error设定错误提示。

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     <html xmlns="http://www.w3.org/1999/xhtml" >
     <head>
         <title>Untitled Page</title>
          <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
          <script type="text/javascript">
         jQuery(document).ready(function(){
            $.ajax({
                 type: "get",
                 async: false,
                 url: "https://api.douban.com/v2/book/search?q=javascript&count=1",
                 dataType: "jsonp",
                 jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
                 jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
                 success: function(json){
                     alert(json.total);
                 },
                 error: function(){
                     alert('fail');
                 }
             });
         });
         </script>
         </head>
      <body>
      </body>
     </html>
    

      

    4.6 jsonp的总结

    1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

    2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。

    3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

    4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。

    总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变这一点!

     



     

  • 相关阅读:
    小程序排错(redis导致)
    linux系统删除-开头文件或目录
    nginx 反向代理
    memcache
    一次故障过程
    json.Decoder vs json.Unmarshal
    ssl中间证书
    作业10:String类
    Angular6如何引入jQuery-knob
    OpenJdk源码下载
  • 原文地址:https://www.cnblogs.com/skyflask/p/9459309.html
Copyright © 2011-2022 走看看