Python之路--Django--Ajax、同源策略、Jsonp、CORS

1、Json简介

一、什么是Json

定义:javascript

  JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用彻底独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提高网络传输效率。html

 

讲json对象,不得不提到JS对象:前端

合格的json对象:java

["one", "two", "three"] { "one": 1, "two": 2, "three": 3 } {"names": ["张三", "李四"] } [ { "name": "张三"}, {"name": "李四"} ] 

不合格的json对象:jquery

{ name: "张三", 'age': 32 }                     // 属性名必须使用双引号 [32, 64, 128, 0xFFF] // 不能使用十六进制值 { "name": "张三", "age": undefined }            // 不能使用undefined { "name": "张三", "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'), "getName":  function() {return this.name;}    // 不能使用函数和日期对象 } 

 

二、stringify与parse方法

JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象  eg: console.log(JSON.parse('{"name":"Yuan"}')); console.log(JSON.parse('{name:"Yuan"}')) ;   // 错误 console.log(JSON.parse('[12,undefined]')) ;   // 错误 JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。  eg: console.log(JSON.stringify({'name':"egon"})) ; 

 

2、Ajax简介 

AJAXAsynchronous Javascript And XML)翻译成中文就是异步JavascriptXML”。即便用Javascript语言与服务器进行异步交互,传输的数据为XML(固然,传输的数据不仅是XML)。ajax

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

AJAX除了异步的特色外,还有一个就是:浏览器页面局部刷新;(这一特色给用户的感觉是在不知不觉中完成请求和响应过程)django

 

一、AJAX常见应用情景

  当咱们在百度中输入一个“老字后,会立刻出现一个下拉列表!列表中显示的是包含“老字的4个关键字。编程

其实这里就使用了AJAX技术!当文件框发生了输入变化时,浏览器会使用AJAX技术向服务器发送一个请求,查询包含字的前10个关键字,而后服务器会把查询到的结果响应给浏览器,最后浏览器把这4个关键字显示在下拉列表中。json

  • 整个过程当中页面没有刷新,只是刷新页面中的局部位置而已!
  • 当请求发出后,浏览器还能够进行其余操做,无需等待服务器的响应!

  当输入用户名后,把光标移动到其余表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会查询名为zhangSan的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户已经存在了,浏览器在获得结果后显示用户名已被注册!后端

  • 整个过程当中页面没有刷新,只是局部刷新了;
  • 在请求发出后,浏览器不用等待服务器响应结果就能够进行其余操做;

 

二、Ajax的优缺点

优势:

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

 

3、jquery实现的ajax

{% load staticfiles %} <!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="{% static 'JS/jquery-3.1.1.js' %}"></script>
</head>
<body>

<button class="send_Ajax">send_Ajax</button>

<script>
      //$.ajax的两种使用方式:

      //$.ajax(settings);
      //$.ajax(url,[settings]);
 $(".send_Ajax").click(function(){ $.ajax({ url:"/handle_Ajax/", type:"POST", data:{username:"Yuan",password:123}, success:function(data){ alert(data) }, //=================== error============
 error: function (jqXHR, textStatus, err) { // jqXHR: jQuery加强的xhr
                        // textStatus: 请求完成状态
                        // err: 底层经过throw抛出的异常对象,值与错误类型有关
 console.log(arguments); }, //=================== complete============
 complete: function (jqXHR, textStatus) { // jqXHR: jQuery加强的xhr
                    // textStatus: 请求完成状态 success | error
 console.log('statusCode: %d, statusText: %s', jqXHR.status, jqXHR.statusText); console.log('textStatus: %s', textStatus); }, //=================== statusCode============
 statusCode: { '403': function (jqXHR, textStatus, err) { console.log(arguments); //注意:后端模拟errror方式:HttpResponse.status_code=500
 }, '400': function () { } } }) }) </script>
</body>
</html>

views.py

import json,time def index(request): return render(request,"index.html") def handle_Ajax(request): username=request.POST.get("username") password=request.POST.get("password") print(username,password) time.sleep(10) return HttpResponse(json.dumps("Error Data!"))

 

一、$.ajax参数

请求参数

######################------------data---------################
 data: 当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式 (urlencoded:?a=1&b=2)发送给服务端;此外,ajax默认以get方式发送请求。 function testData() { $.ajax("/test",{     //此时的data是一个json形式的对象 data:{ a:1, b:2 } }); //?a=1&b=2
######################------------processData---------################
 processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理;if为false, 那么对data:{a:1,b:2}会调用json对象的toString()方法,即{a:1,b:2}.toString() ,最后获得一个[object,Object]形式的结果。 ######################------------contentType---------################
 contentType:默认值: "application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。 用来指明当前请求的数据编码格式;urlencoded:?a=1&b=2;若是想以其余方式提交数据, 好比contentType:"application/json",即向服务器发送一个json字符串: $.ajax("/ajax_get",{ data:JSON.stringify({ a:22, b:33 }), contentType:"application/json", type:"POST", }); //{a: 22, b: 33} 注意:contentType:"application/json"一旦设定,data必须是json字符串,不能是json对象 views.py: json.loads(request.body.decode("utf8")) ######################------------traditional---------################
 traditional:通常是咱们的data数据有数组时会用到 :data:{a:22,b:33,c:["x","y"]}, traditional为false会对数据进行深层次迭代;

响应参数

dataType: 预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。默认不须要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;好比咱们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容进行一个json格式的转换,if转换成功,咱们在success的回调函数里就会获得一个json格式的对象;转换失败就会触发error这个回调函数。若是咱们明确地指定目标类型,就可使用data Type。

dataType的可用值:html|xml|json|text|script
见下dataType实例

 

示例:

from django.shortcuts import render,HttpResponse from django.views.decorators.csrf import csrf_exempt # Create your views here.

import json def login(request): return render(request,'Ajax.html') def ajax_get(request): l=['alex','little alex'] dic={"name":"alex","pwd":123} #return HttpResponse(l) #元素直接转成字符串alexlittle alex
    #return HttpResponse(dic) #字典的键直接转成字符串namepwd
    return HttpResponse(json.dumps(l)) return HttpResponse(json.dumps(dic))# 传到前端的是json字符串,要想使用,须要JSON.parse(data)

//--------------------------------------------------- function testData() { $.ajax('ajax_get', { success: function (data) { console.log(data); console.log(typeof(data)); //console.log(data.name); //JSON.parse(data); //console.log(data.name); }, //dataType:"json", } )} 注解:Response Headers的content Type为text/html,因此返回的是String;但若是咱们想要一个json对象 设定dataType:"json"便可,至关于告诉ajax方法把服务器返回的数据转成json对象发送到前端.结果为object 固然, return HttpResponse(json.dumps(a),content_type="application/json") 这样就不须要设定dataType:"json"了。 content_type="application/json"和content_type="json"是同样的!

 

二、csrf跨站请求伪造

方式1:

$.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }}' }, });

方式2:

<form> {% csrf_token %} </form><br><br><br>$.ajax({<br>...<br>data:{ "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val(); 1 }<br>})

方式3:

<script src="{% static 'js/jquery.cookie.js' %}"></script> $.ajax({ headers:{"X-CSRFToken":$.cookie('csrftoken')}, })

 

三、Ajax(FormData)

<h3>Ajax上传文件</h3>

<p><input type="text" name="username" id="username" placeholder="username"></p>
<p><input type="file" name="upload_file_ajax" id="upload_file_ajax"></p>

<button id="upload_button">提交</button> {#注意button标签不要用在form表单中使用#} <script> $("#upload_button").click(function(){ var username=$("#username").val(); var upload_file=$("#upload_file_ajax")[0].files[0]; var formData=new FormData(); formData.append("username",username); formData.append("upload_file_ajax",upload_file); $.ajax({ url:"/upload_file/", type:"POST", data:formData, contentType:false, processData:false, success:function(){ alert("上传成功!") } }); }) </script>

views.py

def index(request): return render(request,"index.html") def upload_file(request): print("FILES:",request.FILES) print("POST:",request.POST) return HttpResponse("上传成功!")

 

四、伪造Ajax上传文件 

iframe标签

一个内联框架被用来在当前 HTML 文档中嵌入另外一个文档。

示例:

<iframe src="http://www.baidu.com" width="1000px" height="600px"></iframe>

iframe+form

<h3>伪造Ajax上传文件</h3>
<form action="/upload_file/" method="post" id="form2" target="ifr" enctype="multipart/form-data">
    <p>
        <iframe name="ifr" id="ifr"></iframe></p>
    <p><input type="file" name="upload_file"></p>
    <p><input type="text" name="user"></p>

    <input type="button" value="提交" id="submitBtn">
</form>

<script> $("#submitBtn").click(function(){ $("#ifr").load(iframeLoaded); $("#form2").submit(); }); function iframeLoaded(){ alert(123) } </script>
views.py def index(request): return render(request,"index.html") def upload_file(request): print("FILES:",request.FILES) print("POST:",request.POST) return HttpResponse("上传成功!")

 

4、同源策略与Jsonp

一、同源策略

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

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

 

项目1:

==================================http://127.0.0.1:8001项目的index <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>


<button>ajax</button> {% csrf_token %} <script> $("button").click(function(){ $.ajax({ url:"http://127.0.0.1:7766/SendAjax/", type:"POST", data:{"username":"yuan","csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()}, success:function(data){ alert(123); alert(data) } }) }) </script>
</body>
</html> ==================================http://127.0.0.1:8001项目的views def index(request): return render(request,"index.html") def ajax(request): import json print(request.POST,"+++++++++++") return HttpResponse(json.dumps("hello"))

项目2: 

==================================http://127.0.0.1:8002项目的index <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>


<button>sendAjax</button> {% csrf_token %} <script> $("button").click(function(){ $.ajax({ url:"/SendAjax/", type:"POST", data:{"username":"yuan","csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()}, success:function(data){ alert(data) } }) }) </script>

</body>
</html> ==================================http://127.0.0.1:8002项目的views def index(request): return render(request,"index.html") from django.views.decorators.csrf import csrf_exempt @csrf_exempt def SendAjax(request): import json print("++++++++") return HttpResponse(json.dumps("hello2"))

当点击项目1的按钮时,发送了请求,可是会发现报错以下:

已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:7766/SendAjax/ 的远程资源。(缘由:CORS 头缺乏 'Access-Control-Allow-Origin')。

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

 

二、Jsonp 

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

<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> # =============================http://127.0.0.1:8002/ from django.views.decorators.csrf import csrf_exempt @csrf_exempt def SendAjax(request): import json print("++++++++") # dic={"k1":"v1"} return HttpResponse("func('yuan')") # return HttpResponse("func('%s')"%json.dumps(dic))

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

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

      通常状况下,咱们但愿这个script标签可以动态的调用,而不是像上面由于固定在html里面因此没等页面显示就执行了,很不灵活。咱们能够经过javascript动态的建立script标签,这样咱们就能够灵活调用远程服务了。

<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数据传入这个方法完成回调:

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

8002的views不改动。

结果是同样的,要注意的是在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>

8002的views不改动。

固然,最简单的形式仍是经过回调函数来处理:

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

<input type="button" onclick="AjaxRequest()" value="跨域Ajax" />


<div id="container"></div>


    <script type="text/javascript">
        function AjaxRequest() { $.ajax({ url: 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403', type: 'GET', dataType: 'jsonp', jsonp: 'callback', jsonpCallback: 'list', success: function (data) { $.each(data.data,function(i){ var item = data.data[i]; var str = "<p>"+ item.week +"</p>"; $('#container').append(str); $.each(item.list,function(j){ var temp = "<a href='" + item.list[j].link +"'>" + item.list[j].name +" </a><br/>"; $('#container').append(temp); }); $('#container').append("<hr/>"); }) } }); } </script>

 

5、CORS

一、简介

  CORS须要浏览器和服务器同时支持。目前,全部浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通讯过程,都是浏览器自动完成,不须要用户参与。对于开发者来讲,CORS通讯与同源的AJAX通讯没有差异,代码彻底同样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感受。

  所以,实现CORS通讯的关键是服务器。只要服务器实现了CORS接口,就能够跨源通讯。

 

二、两种请求

浏览器将CORS请求分红两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时知足如下两大条件,就属于简单请求。

(1) 请求方法是如下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出如下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

凡是不一样时知足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不同的。

* 简单请求和非简单请求的区别?

   简单请求:一次请求
   非简单请求:两次请求,在发送数据以前会先发一次请求用于作“预检”,只有“预检”经过后才再发送一次请求用于数据传输。
* 关于“预检”

- 请求方式:OPTIONS
- “预检”其实作检查,检查若是经过则容许传输数据,检查不经过则再也不发送真正想要发送的消息
- 如何“预检”
     => 若是复杂请求是PUT等请求,则服务端须要设置容许某请求,不然“预检”不经过
        Access-Control-Request-Method
     => 若是复杂请求设置了请求头,则服务端须要设置容许某请求头,不然“预检”不经过
        Access-Control-Request-Headers

支持跨域,简单请求

服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

支持跨域,复杂请求

因为复杂请求时,首先会发送“预检”请求,若是“预检”成功,则发送真实数据。

  • “预检”请求时,容许请求方式则需服务器设置响应头:Access-Control-Request-Method
  • “预检”请求时,容许请求头则需服务器设置响应头:Access-Control-Request-Headers
相关文章
相关标签/搜索