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
相關文章
相關標籤/搜索