AJAX请求和跨域请求详解(原生JS、Jquery)
一、概述
AJAX 是一種在無需重新加載整個網(wǎng)頁的情況下,能夠更新部分網(wǎng)頁的技術(shù)。
AJAX = 異步 JavaScript 和 XML,是一種用于創(chuàng)建快速動態(tài)網(wǎng)頁的技術(shù)。通過在后臺與服務(wù)器進行少量數(shù)據(jù)交換,AJAX 可以使網(wǎng)頁實現(xiàn)異步更新。這意味著可以在不重新加載整個網(wǎng)頁的情況下,對網(wǎng)頁的某部分進行更新。傳統(tǒng)的網(wǎng)頁(不使用 AJAX)如果需要更新內(nèi)容,必需重載整個網(wǎng)頁面。
本博客實驗環(huán)境:
python:2.7.11 web框架:tonado jquery:2.1.1?
二、“偽”AJAX
由于HTML標(biāo)簽的iframe標(biāo)簽具有局部加載內(nèi)容的特性,所以可以使用其來偽造Ajax請求,從而實現(xiàn)頁面異步更新。
<!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動態(tài)賦值 document.getElementById("iframePosition").src = targetUrl;}</script></body> </html> “偽”AJAX實例?
三、原生AJAX
Ajax主要就是使用 【XmlHttpRequest】對象來完成請求的操作,該對象在主流瀏覽器中均存在(除早期的IE),Ajax首次出現(xiàn)IE5.5中存在(ActiveX控件)。
1、XmlHttpRequest對象介紹
XmlHttpRequest對象的主要方法:
a. void open(String method,String url,Boolen async)用于創(chuàng)建請求參數(shù):method: 請求方式(字符串類型),如:POST、GET、DELETE...url: 要請求的地址(字符串類型)async: 是否異步(布爾類型),一般填trueb. void send(String body)用于發(fā)送請求參數(shù):body: 要發(fā)送的數(shù)據(jù)(字符串類型)c. void setRequestHeader(String header,String value)用于設(shè)置請求頭參數(shù):header: 請求頭的key(字符串類型)vlaue: 請求頭的value(字符串類型)d. String getAllResponseHeaders()獲取所有響應(yīng)頭返回值:響應(yīng)頭數(shù)據(jù)(字符串類型)e. String getResponseHeader(String header)獲取響應(yīng)頭中指定header的值參數(shù):header: 響應(yīng)頭的key(字符串類型)返回值:響應(yīng)頭中指定的header對應(yīng)的值f. void abort()終止請求?
XmlHttpRequest對象的主要屬性:
a. Number readyState狀態(tài)值(整數(shù))詳細(xì):0-未初始化,尚未調(diào)用open()方法;1-啟動,調(diào)用了open()方法,未調(diào)用send()方法;2-發(fā)送,已經(jīng)調(diào)用了send()方法,未接收到響應(yīng);3-接收,已經(jīng)接收到部分響應(yīng)數(shù)據(jù);4-完成,已經(jīng)接收到全部響應(yīng)數(shù)據(jù);b. Function onreadystatechange當(dāng)readyState的值改變時自動觸發(fā)執(zhí)行其對應(yīng)的函數(shù)(回調(diào)函數(shù))c. String responseText服務(wù)器返回的數(shù)據(jù)(字符串類型)d. XmlDocument responseXML服務(wù)器返回的數(shù)據(jù)(Xml對象)e. Number states狀態(tài)碼(整數(shù)),如:200、404...f. String statesText狀態(tài)文本(字符串),如:OK、NotFound...2、跨瀏覽器支持
XmlHttpRequest支持:
IE7+, Firefox, Chrome, Opera, etc.
IE6, IE5不支持XmlHttpRequest。,所以使用ActiveXObject("Microsoft.XMLHTTP")對象實現(xiàn)。
原生AJAX實例(支持XHR和ActiveXObject):
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><h1>XMLHttpRequest - Ajax請求</h1><input type="button" οnclick="XhrGetRequest();" value="Get發(fā)送請求" /><input type="button" οnclick="XhrPostRequest();" value="Post發(fā)送請求" /><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();// 定義回調(diào)函數(shù)xhr.onreadystatechange = function(){if(xhr.readyState == 4){// 已經(jīng)接收到全部響應(yīng)數(shù)據(jù),執(zhí)行以下操作var data = xhr.responseText;alert(data);}};// 指定連接方式和地址----文件方式xhr.open('POST', "/test", true);// 設(shè)置請求頭xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');// 發(fā)送請求xhr.send('n1=1;n2=2;');}function XhrGetRequest(){var xhr = GetXHR();// 定義回調(diào)函數(shù)xhr.onreadystatechange = function(){if(xhr.readyState == 4){// 已經(jīng)接收到全部響應(yīng)數(shù)據(jù),執(zhí)行以下操作var data = xhr.responseText;alert(data);}};// 指定連接方式和地址----文件方式xhr.open('get', "/test", true);// 發(fā)送請求 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.webfrom 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的類庫,其將復(fù)雜的功能做了上層封裝,使得開發(fā)者可以在其基礎(chǔ)上寫更少的代碼實現(xiàn)更多的功能。
- jQuery 不是生產(chǎn)者,而是大自然搬運工。
- jQuery Ajax本質(zhì) XMLHttpRequest 或 ActiveXObject?
注:2.+版本不再支持IE9以下的瀏覽器
jQuery.ajax(...)部分參數(shù):url:請求地址type:請求方式,GET、POST(1.9.0之后用method)headers:請求頭data:要發(fā)送的數(shù)據(jù)contentType:即將發(fā)送信息至服務(wù)器的內(nèi)容編碼類型(默認(rèn): "application/x-www-form-urlencoded; charset=UTF-8")async:是否異步timeout:設(shè)置請求超時時間(毫秒)beforeSend:發(fā)送請求前執(zhí)行的函數(shù)(全局)complete:完成之后執(zhí)行的回調(diào)函數(shù)(全局)success:成功之后執(zhí)行的回調(diào)函數(shù)(全局)error:失敗之后執(zhí)行的回調(diào)函數(shù)(全局)accepts:通過請求頭發(fā)送給服務(wù)器,告訴服務(wù)器當(dāng)前客戶端課接受的數(shù)據(jù)類型dataType:將服務(wù)器端返回的數(shù)據(jù)轉(zhuǎn)換成指定類型"xml": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成xml格式"text": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成普通文本格式"html": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成普通文本格式,在插入DOM中時,如果包含JavaScript標(biāo)簽,則會嘗試去執(zhí)行。"script": 嘗試將返回值當(dāng)作JavaScript去執(zhí)行,然后再將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成普通文本格式"json": 將服務(wù)器端返回的內(nèi)容轉(zhuǎn)換成相應(yīng)的JavaScript對象"jsonp": JSONP 格式使用 JSONP 形式調(diào)用函數(shù)時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函數(shù)名,以執(zhí)行回調(diào)函數(shù)如果不指定,jQuery 將自動根據(jù)HTTP包MIME信息返回相應(yīng)類型(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 stringconverters: 轉(zhuǎn)換器,將服務(wù)器端的內(nèi)容根據(jù)指定的dataType轉(zhuǎn)換類型,并傳值給success回調(diào)函數(shù)$.ajax({accepts: {mycustomtype: 'application/x-some-custom-type'},// Expect a `mycustomtype` back from serverdataType: 'mycustomtype'// Instructions for how to deserialize a `mycustomtype` converters: {'text mycustomtype': function(result) {// Do Stuffreturn newresult;}},}); Jquery底層AJAX方法 jQuery.get(...)所有參數(shù):url: 待載入頁面的URL地址data: 待發(fā)送 Key/value 參數(shù)。 success: 載入成功時回調(diào)函數(shù)。dataType: 返回內(nèi)容格式,xml, json, script, text, htmljQuery.post(...)所有參數(shù):url: 待載入頁面的URL地址data: 待發(fā)送 Key/value 參數(shù) success: 載入成功時回調(diào)函數(shù)dataType: 返回內(nèi)容格式,xml, json, script, text, htmljQuery.getJSON(...)所有參數(shù):url: 待載入頁面的URL地址data: 待發(fā)送 Key/value 參數(shù)。 success: 載入成功時回調(diào)函數(shù)。jQuery.getScript(...)所有參數(shù):url: 待載入頁面的URL地址data: 待發(fā)送 Key/value 參數(shù)。success: 載入成功時回調(diào)函數(shù)。 封裝請求方法的AJAX方法Jquery AJAX實例:
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><p><input type="button" οnclick="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.webfrom 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
由于瀏覽器存在同源策略機制,同源策略阻止從一個源加載的文檔或腳本獲取或設(shè)置另一個源加載的文檔的屬性。
關(guān)于同源的判定規(guī)則:如果兩個頁面擁有相同的協(xié)議(protocol),端口(如果指定),和主機,那么這兩個頁面就屬于同一個源(origin)。
| URL | 結(jié)果 | 原因 |
| 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 | 失敗 | 協(xié)議不同 |
| http://store.company.com:81/dir/etc.html | 失敗 | 端口不同 |
| http://news.company.com/dir/other.html | 失敗 | 主機名不同 |
?
特別的:由于同源策略是瀏覽器的限制,所以請求的發(fā)送和響應(yīng)是可以進行,只不過瀏覽器不接受罷了。
瀏覽器同源策略并不是對所有的請求均制約:
- 制約:?XmlHttpRequest
- 無效:?img、iframe、script等具有src屬性的標(biāo)簽
?
那么如有解決跨域請求的問題呢?下面提供了兩中方法實現(xiàn)跨域請求,分別是JSONP和CORS。
Jsonp 與 CORS 的比較:
- Jsonp只支持 GET 請求,CORS支持所有類型的HTTP請求。
- Jsonp 的優(yōu)勢在于支持老式瀏覽器,以及可以向不支持CORS的網(wǎng)站請求數(shù)據(jù)。
1、JSONP實現(xiàn)跨域請求
JSONP(JSONP - JSON with Padding是JSON的一種“使用模式”),利用script標(biāo)簽的src屬性(瀏覽器允許script標(biāo)簽跨域)。
基本原理,通過以下幾步完成跨域請求:
1、brower創(chuàng)建script標(biāo)簽,并利用script標(biāo)簽的src屬性發(fā)送跨域請求,獲取服務(wù)器的返回值在<script>標(biāo)簽內(nèi)。
2、server返回函數(shù)調(diào)用語句(myfunc(args);),并將需要返回的值(args)作為函數(shù)參數(shù)一并返回。
3、brower執(zhí)行服務(wù)器返回的調(diào)用函數(shù)的語句(myfunc(args)),對返回值進行操作。
4、brower刪除第一步創(chuàng)建的script標(biāo)簽。
?
?
?JSONP實例一,固定回調(diào)函數(shù)名:
#! /usr/bin/env python # -*- coding:utf-8 -*- # __author__ = "TKQ" import tornado.httpserver import tornado.ioloop import tornado.options import tornado.webfrom 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):#客戶端定義的函數(shù)名必須也為myfunc才會調(diào)用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" οnclick="GetJsonp();" value='提交'/></p><!--<script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>--><script> // 創(chuàng)建script標(biāo)簽跨域請求,并根據(jù)返回函數(shù)myfunc([1,2,3]);執(zhí)行定義的myfunc函數(shù)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" οnclick="GetJsonp();" value='提交'/></p><script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script><script> // 創(chuàng)建script標(biāo)簽跨域請求,并根據(jù)返回函數(shù)myfunc([1,2,3]);執(zhí)行定義的myfunc函數(shù)function GetJsonp(){$.ajax({url: "http://tkq2.com:8000/test",dataType: 'jsonp',jsonpCallback:'myfunc' //自定義了回調(diào)函數(shù)名,默認(rèn)為jQuery自動生成的隨機函數(shù)名。如果不寫回調(diào)函數(shù)名,默認(rèn)執(zhí)行與服務(wù)器返回的函數(shù)名相同的函數(shù)。 })} // 回調(diào)函數(shù)function myfunc(list) {console.log(list);}</script> </body> </html> Jquery的jsonp實例JSONP實例二,可變回調(diào)函數(shù)名:?
實例一中,回調(diào)函數(shù)服務(wù)器端定寫死了,請求端必須定義和服務(wù)器端相同函數(shù)名才行。但作為服務(wù)端應(yīng)該有更好的兼容性,請求端自行決定回調(diào)函數(shù)名字,下面我們來實現(xiàn)這個功能。
原理:http://tkq2.com:8000/test?jsonpcallback=myfunc,通過請求中攜帶jsonpcallback=myfunc參數(shù),使服務(wù)端獲取到自定義的回調(diào)函數(shù)名。
#! /usr/bin/env python # -*- coding:utf-8 -*- # __author__ = "TKQ" import tornado.httpserver import tornado.ioloop import tornado.options import tornado.webfrom 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" οnclick="GetJsonp();" value='提交'/></p><!--<script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script>--><script> // 創(chuàng)建script標(biāo)簽跨域請求,并根據(jù)返回函數(shù)myfunc([1,2,3]);執(zhí)行定義的myfunc函數(shù)function GetJsonp(){var tag = document.createElement('script'); //自定義回調(diào)函數(shù)名,jsonpcallback=myfunc字段供服務(wù)端讀取。tag.src = "http://tkq2.com:8000/test?jsonpcallback=myfunc";document.head.appendChild(tag);document.head.removeChild(tag);}function myfunc(list) {console.log(list);} 原生JS實現(xiàn) <!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><p><input type="button" οnclick="GetJsonp();" value='提交'/></p><script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script><script> // 創(chuàng)建script標(biāo)簽跨域請求,并根據(jù)返回函數(shù)myfunc([1,2,3]);執(zhí)行定義的myfunc函數(shù)function GetJsonp(){$.ajax({url: "http://tkq2.com:8000/test",dataType: 'jsonp',jsonp:'jsonpcallback', //傳遞給請求處理程序或頁面的,用以獲得jsonp回調(diào)函數(shù)名的參數(shù)名(一般默認(rèn)為:callback)jsonpCallback:'myfunc' //自定義了回調(diào)函數(shù)名,默認(rèn)為jQuery自動生成的隨機函數(shù)名。如果不寫回調(diào)函數(shù)名,默認(rèn)執(zhí)行與服務(wù)器返回的函數(shù)名相同的函數(shù)。 })} // 回調(diào)函數(shù)function myfunc(list) {console.log(list);}</script> </body> </html> Jquery實現(xiàn)JSONP實例三,江西衛(wèi)視節(jié)目單獲取:
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><p><input type="button" οnclick="GetJsonp();" value='JS提交'/><input type="button" οnclick="JQJsonp();" value='JQ提交'/></p><script type="text/javascript" src='{{static_url("jquery-2.1.1.min.js")}}'></script><script>//回調(diào)函數(shù)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> 江西衛(wèi)視節(jié)目單獲取?
2、CORS跨域資源共享
?隨著技術(shù)的發(fā)展,現(xiàn)在的瀏覽器可以支持主動設(shè)置從而允許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質(zhì)是設(shè)置響應(yīng)頭,使得瀏覽器允許跨域請求。
這種實現(xiàn)方式:請求端和普通的AJAX方法相同,但服務(wù)器端需要做相應(yīng)的配置。
?簡單請求 OR 非簡單請求
條件:1、請求方式:HEAD、GET、POST2、請求頭信息:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type 對應(yīng)的值是以下三個中的任意一個application/x-www-form-urlencodedmultipart/form-datatext/plain 注意:同時滿足以上兩個條件時,則是簡單請求,否則為復(fù)雜請求CORS中簡單請求和非簡單請求的區(qū)別是什么?
簡單請求:一次請求 非簡單請求:兩次請求,在發(fā)送數(shù)據(jù)之前會先發(fā)一次請求用于做“預(yù)檢”,只有“預(yù)檢”通過后才再發(fā)送一次請求用于數(shù)據(jù)傳輸。?關(guān)于“預(yù)檢”
- 請求方式:OPTIONS - “預(yù)檢”其實做檢查,檢查如果通過則允許傳輸數(shù)據(jù),檢查不通過則不再發(fā)送真正想要發(fā)送的消息 - 如何“預(yù)檢”=> 如果復(fù)雜請求是PUT等請求,則服務(wù)端需要設(shè)置允許某請求,否則“預(yù)檢”不通過Access-Control-Request-Method=> 如果復(fù)雜請求設(shè)置了請求頭,則服務(wù)端需要設(shè)置允許某請求頭,否則“預(yù)檢”不通過Access-Control-Request-Headers基于cors實現(xiàn)AJAX請求:
a、支持跨域,簡單請求
服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Allow-Origin = '域名' 或 '*'
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><h1>CORS</h1><input type="button" οnclick="XhrGetRequest();" value="Get發(fā)送請求" /><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設(shè)置: 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、支持跨域,復(fù)雜請求
由于復(fù)雜請求時,首先會發(fā)送“預(yù)檢”請求,如果“預(yù)檢”成功,則發(fā)送真實數(shù)據(jù)。
- "預(yù)檢“請求前,先需要設(shè)置預(yù)檢接收源地址:Access-Control-Allow-Origin
- “預(yù)檢”請求時,允許請求方式則需服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Request-Method
- “預(yù)檢”請求時,允許請求頭則需服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Request-Headers
- “預(yù)檢”緩存時間,服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Max-Age
預(yù)檢完成后,在發(fā)送負(fù)載請求,例如put方法,該方法如同簡單方法一樣,需要設(shè)置接收源地址:Access-Control-Allow-Origin
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><h1>CORS</h1><input type="button" οnclick="XhrGetRequest();" value="put發(fā)送請求js" /><input type="button" οnclick="JqSendRequest();" value="put發(fā)送請求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):# 復(fù)雜請求方法putdef put(self):self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")self.write('put success')# 預(yù)檢方法設(shè)置def options(self, *args, **kwargs):#設(shè)置預(yù)檢方法接收源self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")#設(shè)置預(yù)復(fù)雜方法自定義請求頭h1和h2self.set_header('Access-Control-Allow-Headers', "h1,h2")#設(shè)置允許哪些復(fù)雜請求方法self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")#設(shè)置預(yù)檢緩存時間秒,緩存時間內(nèi)發(fā)送請求無需再預(yù)檢self.set_header('Access-Control-Max-Age', 10)c、跨域獲取響應(yīng)頭
默認(rèn)獲取到的所有響應(yīng)頭只有基本信息,如果想要獲取自定義的響應(yīng)頭,則需要再服務(wù)器端設(shè)置Access-Control-Expose-Headers。
<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><h1>CORS</h1><input type="button" οnclick="XhrGetRequest();" value="put發(fā)送請求js" /><input type="button" οnclick="JqSendRequest();" value="put發(fā)送請求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);// 獲取響應(yīng)頭 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);// 獲取響應(yīng)頭 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):# 復(fù)雜請求方法putdef put(self):self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")# 自定義headerself.set_header('cos1', "cos_value1")self.set_header('cos2', "cos_value2")#設(shè)置允許請求端接收自定義的請求頭,否則請求段無法接收自定義的請求頭self.set_header('Access-Control-Expose-Headers', "cos1,cos2")self.write('put success')# 預(yù)檢方法設(shè)置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
在跨域請求中,默認(rèn)情況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書無論在預(yù)檢請求中或是在實際請求都是不會被發(fā)送。
如果想要發(fā)送:
- 瀏覽器端:XMLHttpRequest的withCredentials為true
- 服務(wù)器端:Access-Control-Allow-Credentials為true
- 注意:服務(wù)器端響應(yīng)的?Access-Control-Allow-Origin 不能是通配符 *(包括options方法)
?
class CORSHandler(tornado.web.RequestHandler):# 復(fù)雜請求方法putdef put(self):self.set_header('Access-Control-Allow-Origin', "http://tkq1.com:8000")# 設(shè)置允許跨域傳輸cookieself.set_header('Access-Control-Allow-Credentials','true')self.set_cookie('myck', 'c_value')self.write('put success')# 預(yù)檢方法設(shè)置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) #設(shè)置允許跨域傳輸cookieself.set_header('Access-Control-Allow-Credentials', 'true')?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/tkqasn/p/5869175.html
總結(jié)
以上是生活随笔為你收集整理的AJAX请求和跨域请求详解(原生JS、Jquery)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RedHat 6 安装配置Tomcat
- 下一篇: Servlet和JSP规范及版本对应关系