tornado框架之路三之ajax

1、ajaxjavascript

一、傳統的Web應用html

一個簡單操做須要從新加載全局數據java

二、AJAXpython

AJAX即「Asynchronous Javascript And XML」(異步JavaScript和XML),是指一種建立交互式網頁應用的網頁開發技術jquery

  • 異步的JavaScript: 使用 【JavaScript語言】 以及 相關【瀏覽器提供類庫】 的功能向服務端發送請求,當服務端處理完請求以後,【自動執行某個JavaScript的回調函數】。 PS:以上請求和響應的整個過程是【偷偷】進行的,頁面上無任何感知。
  • XML XML是一種標記語言,是Ajax在和後臺交互時傳輸數據的格式之一

利用AJAX能夠作: 一、註冊時,輸入用戶名自動檢測用戶是否已經存在。 二、登錄時,提示用戶名密碼錯誤 三、刪除數據行時,將行ID發送到後臺,後臺在數據庫中刪除,數據庫刪除成功後,在頁面DOM中將數據行也刪除。web

「僞」AJAXajax

因爲HTML標籤的iframe標籤具備局部加載內容的特性,因此可使用其來僞造Ajax請求。數據庫

<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div>
            <p>請輸入要加載的地址:<span id="currentTime"></span></p>
            <p>
                <input id="url" type="text" />
                <input type="button" value="刷新" onclick="LoadPage();">
            </p>
        </div>
        <div>
            <h3>加載頁面位置:</h3>
            <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe>
        </div>
        <script type="text/javascript">
            window.onload= function(){
                var myDate = new Date();
                document.getElementById('currentTime').innerText = myDate.getTime();
            };
            function LoadPage(){
                var targetUrl =  document.getElementById('url').value;
                document.getElementById("iframePosition").src = targetUrl;
            }
        </script>
    </body>
</html>

原生AJAXjson

Ajax主要就是使用 【XmlHttpRequest】對象來完成請求的操做,該對象在主流瀏覽器中均存在(除早起的IE),Ajax首次出現IE5.5中存在(ActiveX控件)跨域

一、XmlHttpRequest對象介紹

XmlHttpRequest對象的主要方法:

a. void open(String method,String url,Boolen async)
   用於建立請求
   參數:
       method: 請求方式(字符串類型),如:POST、GET、DELETE...
       url:    要請求的地址(字符串類型)
       async:  是否異步(布爾類型)
 
b. void send(String body)
    用於發送請求
    參數:
        body: 要發送的數據(字符串類型)

c. void setRequestHeader(String header,String value)
    用於設置請求頭
    參數:
        header: 請求頭的key(字符串類型)
        vlaue:  請求頭的value(字符串類型)

d. String getAllResponseHeaders()
    獲取全部響應頭
    返回值:
        響應頭數據(字符串類型)

e. String getResponseHeader(String header)
    獲取響應頭中指定header的值
    參數:
        header: 響應頭的key(字符串類型)
    返回值:
        響應頭中指定的header對應的值

f. void abort()
    終止請求

XmlHttpRequest對象的主要屬性:

a. Number readyState
   狀態值(整數)
   詳細:
      0-未初始化,還沒有調用open()方法;
      1-啓動,調用了open()方法,未調用send()方法;
      2-發送,已經調用了send()方法,未接收到響應;
      3-接收,已經接收到部分響應數據;
      4-完成,已經接收到所有響應數據;

b. Function onreadystatechange
   當readyState的值改變時自動觸發執行其對應的函數(回調函數)

c. String responseText
   服務器返回的數據(字符串類型)

d. XmlDocument responseXML
   服務器返回的數據(Xml對象)

e. Number states
   狀態碼(整數),如:200、404...

f. String statesText

   狀態文本(字符串),如:OK、NotFound...

二、跨瀏覽器支持

  XmlHttpRequest IE7+, Firefox, Chrome, Opera, etc.

  • ActiveXObject("Microsoft.XMLHTTP") IE6, IE5
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>XMLHttpRequest - Ajax請求</h1>
    <input type="button" onclick="XhrGetRequest();" value="Get發送請求" />
    <input type="button" onclick="XhrPostRequest();" value="Post發送請求" />

    <script type="text/javascript">

        function GetXHR(){    //看瀏覽器中是XMLHttpRequest仍是ActiveXObject
            var xhr = null;
            if(XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else{
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xhr;  //返回一個對象

        }

        function XhrPostRequest(){
            var xhr = GetXHR();
            // 定義回調函數
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 已經接收到所有響應數據,執行如下操做
                    var data = xhr.responseText;
                    console.log(data);
                }
            };
            // 指定鏈接方式和地址----文件方式
            xhr.open('POST', "/login", true);  //True是設置是否異步
            // post請求必須設置請求頭
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
            // 發送請求
            xhr.send('n1=1;n2=2;');
        }

        function XhrGetRequest(){
            var xhr = GetXHR();
            // 定義回調函數
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 已經接收到所有響應數據,執行如下操做
                    var data = xhr.responseText;
                    console.log(data);
                }
            };
            // 指定鏈接方式和地址----文件方式
            xhr.open('get', "/login", true);
            // 發送請求
            xhr.send();
        }
    </script>
</body>
</html>
原生AJAX

jQuery Ajax

jQuery其實就是一個JavaScript的類庫,其將複雜的功能作了上層封裝,使得開發者能夠在其基礎上寫更少的代碼實現更多的功能。

  • jQuery 不是生產者,而是大天然搬運工。
  • jQuery Ajax本質 XMLHttpRequest 或 ActiveXObject 

注:2.+版本再也不支持IE9如下的瀏覽器

 jQuery.get(...)
                全部參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數。
                 success: 載入成功時回調函數。
                dataType: 返回內容格式,xml, json,  script, text, html

            jQuery.post(...)
                全部參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數
                 success: 載入成功時回調函數
                dataType: 返回內容格式,xml, json,  script, text, html

            jQuery.getJSON(...)
                全部參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數。
                 success: 載入成功時回調函數。

            jQuery.getScript(...)
                全部參數:
                     url: 待載入頁面的URL地址
                    data: 待發送 Key/value 參數。
                 success: 載入成功時回調函數。

            jQuery.ajax(...)
                部分參數:
                        url:請求地址
                       type:請求方式,GET、POST(1.9.0以後用method)
                    headers:請求頭
                       data:要發送的數據
                contentType:即將發送信息至服務器的內容編碼類型(默認: "application/x-www-form-urlencoded; charset=UTF-8")
                      async:是否異步
                    timeout:設置請求超時時間(毫秒)

                 beforeSend:發送請求前執行的函數(全局)
                   complete:完成以後執行的回調函數(全局)
                    success:成功以後執行的回調函數(全局)
                      error:失敗以後執行的回調函數(全局)

                    accepts:經過請求頭髮送給服務器,告訴服務器當前客戶端課接受的數據類型
                   dataType:將服務器端返回的數據轉換成指定類型
                                   "xml": 將服務器端返回的內容轉換成xml格式
                                  "text": 將服務器端返回的內容轉換成普通文本格式
                                  "html": 將服務器端返回的內容轉換成普通文本格式,在插入DOM中時,若是包含JavaScript標籤,則會嘗試去執行。
                                "script": 嘗試將返回值看成JavaScript去執行,而後再將服務器端返回的內容轉換成普通文本格式
                                  "json": 將服務器端返回的內容轉換成相應的JavaScript對象
                                 "jsonp": JSONP 格式
                                          使用 JSONP 形式調用函數時,如 "myurl?callback=?" jQuery 將自動替換 ? 爲正確的函數名,以執行回調函數

                                  若是不指定,jQuery 將自動根據HTTP包MIME信息返回相應類型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string

                 converters: 轉換器,將服務器端的內容根據指定的dataType轉換類型,並傳值給success回調函數
                         $.ajax({
                              accepts: {
                                mycustomtype: 'application/x-some-custom-type'
                              },
                              
                              // Expect a `mycustomtype` back from server
                              dataType: 'mycustomtype'

                              // Instructions for how to deserialize a `mycustomtype`
                              converters: {
                                'text mycustomtype': function(result) {
                                  // Do Stuff
                                  return newresult;
                                }
                              },
                            });
jQuery Ajax 方法列表
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <p>
        <input type="button" onclick="JqSendRequest();" value='Ajax請求' />
    </p>
    <script type="text/javascript" src="/c/static/jquery-1.9.1.min.js"></script>
    <script>
        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'GET',
                data:{"k1":"v1"},  //向服務端發送內容,服務端能夠經過self.get_argument("k1")獲取
                dataType: 'text',
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data,statusText);
                }
            })
        }
    </script>
</body>
</html>
基於jQueryAjax

2、上傳文件

一、Form表單上傳

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>上傳文件</title>
</head>
<body>
    <form id="my_form" name="form" action="/index" method="POST"  enctype="multipart/form-data" >
        <input name="fff" id="my_file"  type="file" />
        <input type="submit" value="提交"  />
    </form>
</body>
</html>
login.html
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web

class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("login.html")
        
    def post(self, *args, **kwargs):
        file_metas = self.request.files["fff"]  #獲取文件的信息
        print(file_metas)
        for meta in file_metas:
            file_name = meta['filename']
            with open(file_name, 'wb') as up:
                up.write(meta['body'])
settings = {
    'template_path': 'tpl',
    'static_path': 'st',

}

application = tornado.web.Application([
    (r"/login", LoginHandler),
], **settings)


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
start.py

二、AJAX上傳

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <input type="file" id="img" />
    <input type="button" onclick="UploadFile();" />
    <script>
        function UploadFile(){
            //獲取文件對象
            var fileObj = document.getElementById("img").files[0];
            //建立form對象
            var form = new FormData();
            form.append("k1", "v1");  //爲後臺發送數據
            form.append("fff", fileObj);
            var xhr = new XMLHttpRequest();
            xhr.open("post", '/login', true);
            xhr.send(form); //發送form表單
        }
    </script>
</body>
</html>
HTML - XMLHttpRequest
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="{{static_url('jquery-1.9.1.min.js')}}"></script>
</head>
<body>
<h1>1223</h1>
 <input type="file" id="img" />
    <input type="button" onclick="UploadFile();" />
    <script>
        function UploadFile(){
            var fileObj = $("#img")[0].files[0];
            var form = new FormData();
            form.append("k1", "v1");
            form.append("fff", fileObj);
            $.ajax({
                type:'POST',
                url: '/login',
                data: form,
                processData: false,  // tell jQuery not to process the data
                contentType: false,  // tell jQuery not to set contentType
                success: function(arg){
                    console.log(arg);
                }
            })
        }
    </script>
</body>
</html>
HTML - jQuery
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
       <script src="{{static_url('jquery-1.9.1.min.js')}}"></script>
</head>
<body>
    <form id="my_form" name="form" action="/login" method="POST"  enctype="multipart/form-data" >
        <div id="main">
            <input name="fff" id="my_file"  type="file" />
            <input type="button" name="action" value="Upload" onclick="redirect()"/>
            <iframe id='my_iframe' name='my_iframe' src=""  class="hide"></iframe>
        </div>
    </form>

    <script>
        function redirect(){
            document.getElementById('my_iframe').onload = Testt;
            document.getElementById('my_form').target = 'my_iframe';
            document.getElementById('my_form').submit();
        }
        function Testt(ths){
            var t = $("#my_iframe").contents().find("body").text();
            console.log(t);
            console.log("1212111")
        }
    </script>
</body>
</html>
HTML - iframe
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web

class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("login.html")

    def post(self, *args, **kwargs):

        file_metas = self.request.files["fff"]  #獲取文件的信息
        print(file_metas)
        for meta in file_metas:
            file_name = meta['filename']
            with open(file_name, 'wb') as up:
                up.write(meta['body'])
settings = {
    'template_path': 'tpl',
    'static_path': 'static',
}

application = tornado.web.Application([
    (r"/login", LoginHandler),
], **settings)


if __name__ == "__main__":
    application.listen(8899)
    tornado.ioloop.IOLoop.instance().start()
start.py

3、CSRF

CSRF(Cross-site request forgery跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding

若是在配置中加入"xsrf_cookies": True,  post請求就會開啓驗證,若是爲驗證經過,post請求不會經過,若是想經過驗證,就在html的body部分加入

{% raw xsrf_form_html() %}--------------->第一次get請求的時候,會隨機生成一個具備驗證功能的字符串,當咱們經過post方式進行請求的時候,就會經過驗證

settings = {
    "xsrf_cookies": True,
}
application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/login", LoginHandler),
], **settings)
<form action="/new_message" method="post">
  {% raw  xsrf_form_html()  %}
  <input type="text" name="message"/>
  <input type="submit" value="Post"/>
</form>
function getCookie(name) {
    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
    return r ? r[1] : undefined;
}

jQuery.postJSON = function(url, args, callback) {
    args._xsrf = getCookie("_xsrf");
    $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST",
        success: function(response) {
        callback(eval("(" + response + ")"));
    }});
};
使用 - AJAX

4、跨域AJAX

1.什麼引發了ajax跨域不能的問題
ajax自己其實是經過XMLHttpRequest對象來進行數據的交互,而瀏覽器出於安全考慮,不容許js代碼進行跨域操做,因此會警告。

特別的:因爲同源策略是瀏覽器的限制,因此請求的發送和響應是能夠進行,只不過瀏覽器不接受罷了。

瀏覽器同源策略並非對全部的請求均制約:

  • 制約: XmlHttpRequest
  • 不叼: img、iframe、script等具備src屬性的標籤

跨域,跨域名訪問,如:http://www.c1.com 域名向 http://www.c2.com域名發送請求。

一、JSONP實現跨域請求(利用script塊的特性)

JSONP(JSONP - JSON with Padding是JSON的一種「使用模式」),利用script標籤的src屬性(瀏覽器容許script標籤跨域)

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="button" onclick="Jsonp1();"  value='提交'/>
    </p>

    <p>
        <input type="button" onclick="Jsonp2();" value='提交'/>
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function Jsonp1(){
            var tag = document.createElement('script');
            tag.src = "http://c2.com:8000/test/";
            document.head.appendChild(tag);
            document.head.removeChild(tag);

        }

        function Jsonp2(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'GET',
                dataType: 'JSONP',
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>
基於JSONP實現跨域Ajax

JSONP就是ajax利用投機取巧的方式,本身不能進行跨域請求從而利用建立一些能進行跨域請求的標籤來(通常都是script標籤)進行跨域請求操做,若是想獲取被請求端發來的數據,那麼須要請求一端寫一個函數,函數內部用於獲取內容,而被請求一端須要將要發送的數據也放到同一個函數名中的函數中進行發送

二、CORS(客戶端不變,服務端設置響應頭)

隨着技術的發展,如今的瀏覽器能夠支持主動設置從而容許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質是設置響應頭,使得瀏覽器容許跨域請求。

* 簡單請求 OR 非簡單請求

條件:
    一、請求方式:HEAD、GET、POST
    二、請求頭信息:
        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

a、支持跨域,簡單請求(在服務端加響應頭,帶相應頭就能過來)

服務器設置響應頭:Access-Control-Allow-Origin = '域名' 或 '*'      *表示全部的域名均可以訪問

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open('GET', "http://c2.com:8000/test/", true);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'GET',
                dataType: 'text',
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }
    </script>
</body>
</html>
html
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 
        self.write('{"status": true, "data": "seven"}')
python

b、支持跨域,複雜請求

因爲複雜請求時,首先會發送「預檢」請求,若是「預檢」成功,則發送真實數據。

  • 「預檢」請求時,容許請求方式則需服務器設置響應頭:Access-Control-Request-Method
  • 「預檢」請求時,容許請求頭則需服務器設置響應頭:Access-Control-Request-Headers
  • 「預檢」緩存時間,服務器設置響應頭:Access-Control-Max-Age
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open('PUT', "http://c2.com:8000/test/", true);
            xhr.setRequestHeader('k1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: 'PUT',
                dataType: 'text',
                headers: {'k1': 'v1'},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }
    </script>
</body>
</html>
html
class MainHandler(tornado.web.RequestHandler):
    
    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.write('{"status": true, "data": "seven"}')

    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
        self.set_header('Access-Control-Allow-Headers', "k1,k2")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10)
python
相關文章
相關標籤/搜索