tornado框架之路三之ajax


一、ajax

1、傳統的Web應用

一個簡單操作需要重新加載全局數據

2、AJAX

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

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

利用AJAX可以做: 1、注冊時,輸入用戶名自動檢測用戶是否已經存在。 2、登陸時,提示用戶名密碼錯誤 3、刪除數據行時,將行ID發送到后台,后台在數據庫中刪除,數據庫刪除成功后,在頁面DOM中將數據行也刪除。

“偽”AJAX

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

原生AJAX

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

1、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...

2、跨瀏覽器支持

  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

二、上傳文件

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

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

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

四、跨域AJAX

1.什么引起了ajax跨域不能的問題
ajax本身實際上是通過XMLHttpRequest對象來進行數據的交互,而瀏覽器出於安全考慮,不允許js代碼進行跨域操作,所以會警告。

特別的:由於同源策略是瀏覽器的限制,所以請求的發送和響應是可以進行,只不過瀏覽器不接受罷了。

瀏覽器同源策略並不是對所有的請求均制約:

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

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

1、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標簽)進行跨域請求操作,如果想獲取被請求端發來的數據,那么需要請求一端寫一個函數,函數內部用於獲取內容,而被請求一端需要將要發送的數據也放到同一個函數名中的函數中進行發送

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

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

* 簡單請求 OR 非簡單請求

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM