AJAX請求和跨域請求詳解(原生JS、Jquery)


一、概述

AJAX 是一種在無需重新加載整個網頁的情況下,能夠更新部分網頁的技術。

AJAX = 異步 JavaScript 和 XML,是一種用於創建快速動態網頁的技術。通過在后台與服務器進行少量數據交換,AJAX 可以使網頁實現異步更新。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。傳統的網頁(不使用 AJAX)如果需要更新內容,必需重載整個網頁面。

本博客實驗環境:

python:2.7.11
web框架:tonado
jquery:2.1.1

 

二、“偽”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>請輸入要加載的地址:</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;
//                為iframe的src動態賦值
                document.getElementById("iframePosition").src = targetUrl;
            }

        </script>

    </body>
</html>
“偽”AJAX實例

 

三、原生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:  是否異步(布爾類型),一般填true
 
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.

IE6, IE5不支持XmlHttpRequest。,所以使用ActiveXObject("Microsoft.XMLHTTP")對象實現。

原生AJAX實例(支持XHR和ActiveXObject):

<!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(){
            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;
                    alert(data);
                }
            };
            // 指定連接方式和地址----文件方式
            xhr.open('POST', "/test", true);
            // 設置請求頭
            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;
                    alert(data);
                }
            };
            // 指定連接方式和地址----文件方式
            xhr.open('get', "/test", true);
            // 發送請求
            xhr.send();
        }

    </script>

</body>
</html>
原生AJAX前端代碼
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options
define("port", default=8888, help="run on the given port", type=int)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("AJAX.html")

class TestHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("hello ajax get method!")
    def post(self):
        n1=self.get_argument("n1")
        n2=self.get_argument("n2")
        addvalue=int(n1)+int(n2)
        self.write("n1+n2=%s"%addvalue)



if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = tornado.web.Application(
        handlers=[(r"/", IndexHandler),
                  (r"/test",TestHandler)]
    ,template_path="template")

    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()
后端tornado代碼

 

四、jQuery Ajax

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

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

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

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方法
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: 載入成功時回調函數。
封裝請求方法的AJAX方法

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='{{static_url("jquery-2.1.1.min.js")}}'></script>
    <script>

        function JqSendRequest(){
            $.ajax({
                url: "/test",
                type: 'GET',
                dataType: 'text',
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data, statusText, xmlHttpRequest)
                }
            })
        }
    </script>
</body>
</html>
Jquery實例前端
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options
define("port", default=8888, help="run on the given port", type=int)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("JQ.html")

class TestHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("hello ajax get method!")
    def post(self):
        n1=self.get_argument("n1")
        n2=self.get_argument("n2")
        addvalue=int(n1)+int(n2)
        self.write("n1+n2=%s"%addvalue)



if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = tornado.web.Application(
        handlers=[(r"/", IndexHandler),
                  (r"/test",TestHandler)]
    ,template_path="template",static_path= 'statics')

    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()
后端tornado代碼

 

五、跨域AJAX

由於瀏覽器存在同源策略機制,同源策略阻止從一個源加載的文檔或腳本獲取或設置另一個源加載的文檔的屬性。

關於同源的判定規則:如果兩個頁面擁有相同的協議(protocol),端口(如果指定),和主機,那么這兩個頁面就屬於同一個源(origin)。

URL 結果 原因
http://store.company.com/dir/page.html 參照對象
http://store.company.com/dir2/other.html 成功  
http://store.company.com/dir/inner/another.html 成功  
https://store.company.com/secure.html 失敗 協議不同
http://store.company.com:81/dir/etc.html 失敗 端口不同
http://news.company.com/dir/other.html 失敗 主機名不同

 

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

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

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

 

那么如有解決跨域請求的問題呢?下面提供了兩中方法實現跨域請求,分別是JSONP和CORS。

Jsonp 與 CORS 的比較:

  • Jsonp只支持 GET 請求,CORS支持所有類型的HTTP請求。
  • Jsonp 的優勢在於支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。

1、JSONP實現跨域請求

JSONP(JSONP - JSON with Padding是JSON的一種“使用模式”),利用script標簽的src屬性(瀏覽器允許script標簽跨域)。

基本原理,通過以下幾步完成跨域請求:

  1、brower創建script標簽,並利用script標簽的src屬性發送跨域請求,獲取服務器的返回值在<script>標簽內。
  2、server返回函數調用語句(myfunc(args);),並將需要返回的值(args)作為函數參數一並返回。

  3、brower執行服務器返回的調用函數的語句(myfunc(args)),對返回值進行操作。

  4、brower刪除第一步創建的script標簽。

 

 

 JSONP實例一,固定回調函數名:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("jsonp.html")

class TestHandler(tornado.web.RequestHandler):
    def get(self):
        #客戶端定義的函數名必須也為myfunc才會調用
        self.write("myfunc([1,2,3]);")

if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = tornado.web.Application(
        handlers=[(r"/", IndexHandler),
                  (r"/test",TestHandler)]
    ,template_path="template",static_path= 'statics')

    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()
后端tornado代碼
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

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

    <!--<script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>-->
    <script>
//        創建script標簽跨域請求,並根據返回函數myfunc([1,2,3]);執行定義的myfunc函數
        function GetJsonp(){
            var tag = document.createElement('script');
            tag.src = "http://tkq2.com:8000/test";
            document.head.appendChild(tag);
            document.head.removeChild(tag);
        }
        function  myfunc(list) {
            console.log(list);
        }


    </script>
</body>
</html>
原生jsonp實例
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

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

    <script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>
    <script>
//        創建script標簽跨域請求,並根據返回函數myfunc([1,2,3]);執行定義的myfunc函數

        function GetJsonp(){
            $.ajax({
                url: "http://tkq2.com:8000/test",
                dataType: 'jsonp',
                jsonpCallback:'myfunc'  //自定義了回調函數名,默認為jQuery自動生成的隨機函數名。如果不寫回調函數名,默認執行與服務器返回的函數名相同的函數。

            })
        }
//      回調函數
        function  myfunc(list) {
            console.log(list);
        }

    </script>
</body>
</html>
Jquery的jsonp實例

JSONP實例二,可變回調函數名: 

實例一中,回調函數服務器端定寫死了,請求端必須定義和服務器端相同函數名才行。但作為服務端應該有更好的兼容性,請求端自行決定回調函數名字,下面我們來實現這個功能。

原理:http://tkq2.com:8000/test?jsonpcallback=myfunc,通過請求中攜帶jsonpcallback=myfunc參數,使服務端獲取到自定義的回調函數名。

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("jq_jsonp.html")

class TestHandler(tornado.web.RequestHandler):
    def get(self):
        func_name=self.get_argument('jsonpcallback')
        self.write("%s([1,2,3]);" %func_name)
if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = tornado.web.Application(
        handlers=[(r"/", IndexHandler),
                  (r"/test",TestHandler)]
    ,template_path="template",static_path= 'statics')

    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()
后端tornado代碼
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

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

    <!--<script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>-->
    <script>
//        創建script標簽跨域請求,並根據返回函數myfunc([1,2,3]);執行定義的myfunc函數
        function GetJsonp(){
            var tag = document.createElement('script');
//自定義回調函數名,jsonpcallback=myfunc字段供服務端讀取。
            tag.src = "http://tkq2.com:8000/test?jsonpcallback=myfunc";
            document.head.appendChild(tag);
            document.head.removeChild(tag);
        }
        function  myfunc(list) {
            console.log(list);
        }
原生JS實現
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

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

    <script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>
    <script>
//        創建script標簽跨域請求,並根據返回函數myfunc([1,2,3]);執行定義的myfunc函數

        function GetJsonp(){
            $.ajax({
                url: "http://tkq2.com:8000/test",
                dataType: 'jsonp',
                jsonp:'jsonpcallback',   //傳遞給請求處理程序或頁面的,用以獲得jsonp回調函數名的參數名(一般默認為:callback)
                jsonpCallback:'myfunc'  //自定義了回調函數名,默認為jQuery自動生成的隨機函數名。如果不寫回調函數名,默認執行與服務器返回的函數名相同的函數。

            })
        }
//      回調函數
        function  myfunc(list) {
            console.log(list);
        }

    </script>
</body>
</html>
Jquery實現

JSONP實例三,江西衛視節目單獲取:

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

    <p>
        <input type="button" onclick="GetJsonp();"  value='JS提交'/>
        <input type="button" onclick="JQJsonp();"  value='JQ提交'/>
    </p>
    <script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>
    <script>
        //回調函數
        function  list(data) {
            console.log(data);
        }
        function GetJsonp(){
            var tag = document.createElement('script');
            tag.src = "http://www.jxntv.cn/data/jmd-jxtv2.html";
            document.head.appendChild(tag);
            document.head.removeChild(tag);
        }
        function JQJsonp(){
            $.ajax({
                url: "http://www.jxntv.cn/data/jmd-jxtv2.html",
                dataType: 'jsonp',
                jsonpCallback:'list'

            })
        }

    </script>
</body>
</html>
江西衛視節目單獲取

 

 

2、CORS跨域資源共享

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

這種實現方式:請求端和普通的AJAX方法相同,但服務器端需要做相應的配置。

 簡單請求 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
 
注意:同時滿足以上兩個條件時,則是簡單請求,否則為復雜請求

CORS中簡單請求和非簡單請求的區別是什么?

簡單請求:一次請求
非簡單請求:兩次請求,在發送數據之前會先發一次請求用於做“預檢”,只有“預檢”通過后才再發送一次請求用於數據傳輸。 

關於“預檢”

- 請求方式:OPTIONS
- “預檢”其實做檢查,檢查如果通過則允許傳輸數據,檢查不通過則不再發送真正想要發送的消息
- 如何“預檢”
     => 如果復雜請求是PUT等請求,則服務端需要設置允許某請求,否則“預檢”不通過
        Access-Control-Request-Method
     => 如果復雜請求設置了請求頭,則服務端需要設置允許某請求頭,否則“預檢”不通過
        Access-Control-Request-Headers

基於cors實現AJAX請求:

a、支持跨域,簡單請求

服務器設置響應頭:Access-Control-Allow-Origin = '域名' 或 '*'

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

    <h1>CORS</h1>
    <input type="button" onclick="XhrGetRequest();" value="Get發送請求" />

    <script type="text/javascript">
        function XhrGetRequest(){
            var xhr =new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var data = xhr.responseText;
                    alert(data);
                }
            };
            xhr.open('get', "http://tkq2.com:8000/test", true);
            xhr.send();
        }
    </script>

</body>
</html>
HTML+JS
tonado設置:
class TestHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")
        self.write('cors get success')

b、支持跨域,復雜請求

由於復雜請求時,首先會發送“預檢”請求,如果“預檢”成功,則發送真實數據。

  • "預檢“請求前,先需要設置預檢接收源地址:Access-Control-Allow-Origin
  • “預檢”請求時,允許請求方式則需服務器設置響應頭:Access-Control-Request-Method
  • “預檢”請求時,允許請求頭則需服務器設置響應頭:Access-Control-Request-Headers
  • “預檢”緩存時間,服務器設置響應頭:Access-Control-Max-Age

預檢完成后,在發送負載請求,例如put方法,該方法如同簡單方法一樣,需要設置接收源地址:Access-Control-Allow-Origin

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

    <h1>CORS</h1>
    <input type="button" onclick="XhrGetRequest();" value="put發送請求js" />
    <input type="button" onclick="JqSendRequest();" value="put發送請求jq" />
    
    <script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>
    <script type="text/javascript">
        function XhrGetRequest(){
            var xhr =new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var data = xhr.responseText;
                    alert(data);
                }
            };
            xhr.open('put', "http://tkq2.com:8000/cors", true);
            xhr.setRequestHeader('h1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://tkq2.com:8000/cors",
                type: 'PUT',
                dataType: 'text',
                headers: {'h1': 'v1'},
                success: function(data, statusText, xmlHttpRequest){
                    alert(data);
                }
            })
        }
    </script>

</body>
</html>
HTML+JS
class CORSHandler(tornado.web.RequestHandler):
    # 復雜請求方法put
    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")
        self.write('put success')
    # 預檢方法設置
    def options(self, *args, **kwargs):
        #設置預檢方法接收源
        self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")
        #設置預復雜方法自定義請求頭h1和h2
        self.set_header('Access-Control-Allow-Headers', "h1,h2")
        #設置允許哪些復雜請求方法
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        #設置預檢緩存時間秒,緩存時間內發送請求無需再預檢
        self.set_header('Access-Control-Max-Age', 10)

c、跨域獲取響應頭

默認獲取到的所有響應頭只有基本信息,如果想要獲取自定義的響應頭,則需要再服務器端設置Access-Control-Expose-Headers。

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

    <h1>CORS</h1>
    <input type="button" onclick="XhrGetRequest();" value="put發送請求js" />
    <input type="button" onclick="JqSendRequest();" value="put發送請求jq" />

    <script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>
    <script type="text/javascript">
        function XhrGetRequest(){
            var xhr =new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var data = xhr.responseText;
                    alert(data);
                    // 獲取響應頭
                    console.log(xhr.getAllResponseHeaders());
                }
            };
            xhr.open('put', "http://tkq2.com:8000/cors", true);
            xhr.setRequestHeader('h1', 'v1');
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://tkq2.com:8000/cors",
                type: 'PUT',
                dataType: 'text',
                headers: {'h1': 'v1'},
                success: function(data, statusText, xmlHttpRequest){
                    alert(data);
                    // 獲取響應頭    Content-Type: text/html; charset=UTF-8  Cos2: cos_value2    Cos1: cos_value1
                    console.log(xmlHttpRequest.getAllResponseHeaders());

                }
            })
        }
    </script>

</body>
</html>
HTML+JS  
class CORSHandler(tornado.web.RequestHandler):
    # 復雜請求方法put
    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")
        # 自定義header
        self.set_header('cos1', "cos_value1")
        self.set_header('cos2', "cos_value2")
        #設置允許請求端接收自定義的請求頭,否則請求段無法接收自定義的請求頭 self.set_header('Access-Control-Expose-Headers', "cos1,cos2")
        self.write('put success')
    # 預檢方法設置
    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")
        self.set_header('Access-Control-Allow-Headers', "h1,h2")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10) 

d、跨域傳輸cookie

在跨域請求中,默認情況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書無論在預檢請求中或是在實際請求都是不會被發送。

如果想要發送:

  • 瀏覽器端:XMLHttpRequest的withCredentials為true
  • 服務器端:Access-Control-Allow-Credentials為true
  • 注意:服務器端響應的 Access-Control-Allow-Origin 不能是通配符 *(包括options方法)
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <h1>CORS</h1>
    <input type="button" onclick="XhrGetRequest();" value="put發送請求js" />
    <input type="button" onclick="JqSendRequest();" value="put發送請求jq" />

    <script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>
    <script type="text/javascript">
        function XhrGetRequest(){
            var xhr =new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var data = xhr.responseText;
                    alert(data);
                }
            };
            xhr.withCredentials = true;//允許跨域發送cookies
            xhr.open('put', "http://tkq2.com:8000/cors", true);

            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://tkq2.com:8000/cors",
                type: 'PUT',
                dataType: 'text',
                xhrFields:{withCredentials: true},//允許跨域發送cookies
                success: function(data, statusText, xmlHttpRequest){
                    alert(data);

                }
            })
        }
    </script>

</body>
</html>
HTML+JS

 

class CORSHandler(tornado.web.RequestHandler):
    # 復雜請求方法put
    def put(self):
        self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")
        # 設置允許跨域傳輸cookie self.set_header('Access-Control-Allow-Credentials','true')
        self.set_cookie('myck', 'c_value')
        self.write('put success')
    # 預檢方法設置
    def options(self, *args, **kwargs):
        self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")
        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
        self.set_header('Access-Control-Max-Age', 10)
        #設置允許跨域傳輸cookie self.set_header('Access-Control-Allow-Credentials', 'true')

 

 

 

 

 


免責聲明!

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



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