1、Django先后端交互之Ajax和跨域问题

1、Ajax介绍

一、概述javascript

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

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

二、使用场景前端

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

三、优缺点java

优势:

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

缺点:

  • AJAX并不适合全部场景,不少时候仍是要使用同步交互;
  • AJAX虽然提升了用户体验,但无形中向服务器发送的请求次数增多了,致使服务器压力增大;
  • 由于AJAX是在浏览器中使用Javascript技术完成的,因此还须要处理浏览器兼容性问题,固然,若是使用jQuery的话,则不用考虑这个问题;

2、经过JavaScript实现Ajax

一、过程和请求相关jquery

使用Ajax的过程:

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

 

XMLHTTPRequest关键知识点:

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

二、经过JavaScript实现Ajax之无后台交互web

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

  

三、经过JavaScript实现Ajax之与后台交互ajax

经过Django实现,其实惟一区别就是在open的时候,把URL修改为Django的一个URL便可,包括GET和POST方法的URL。json

a、urls.py文件后端

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

  

b、views.py文件api

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方法:

 

3、经过jQuery实现Ajax

 一、两个快捷API

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

  

 二、两个不经常使用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);
  });
});

  

三、最经常使用的方法

$.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)。一般在本地和远程的内容编码不一样时使用。

  

  

四、Django中设定状态码

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


4、跨域问题

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的讲解有不少,大概总结以下:

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

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

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

四、恰巧咱们已经知道有一种叫作JSON的纯字符数据格式能够简洁的描述复杂数据,更妙的是JSON还被js原生支持,因此在客户端几乎能够为所欲为的处理这种格式的数据;

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

六、客户端在对JSON文件调用成功以后,也就得到了本身所需的数据,剩下的就是按照本身需求进行处理和展示了,这种获取远程数据的方式看起来很是像AJAX,但其实并不同。

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

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

 

4.4 JavaScript实现跨域

一、咱们知道,哪怕跨域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>
复制代码

  

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

 

二、如今咱们在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的服务者都要面对不少服务对象,而这些服务对象各自的本地函数都不相同啊?咱们接着往下看。

三、聪明的开发者很容易想到,只要服务端提供的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的总结

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

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

三、因此说,其实ajax与jsonp的区别不在因而否跨域,ajax经过服务端代理同样能够实现跨域,jsonp自己也不排斥同域的数据的获取。

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

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

相关文章
相关标签/搜索