概述
對于WEB應用程式:使用者浏覽器發送請求,伺服器接收并處理請求,然後傳回結果,往往傳回就是字元串(HTML),浏覽器将字元串(HTML)渲染并顯示浏覽器上。
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請求。

#urls.py
url(r'^autohome/', views.autohome),
#views.py
from django.shortcuts import render,HttpResponse,redirect
import os
def autohome(request):
return render(request,'autohome.html')
#autohome.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<input type="text" id="txt1">
<input type="button" value="檢視" onclick="changeScr();">
</div>
<iframe id="ifr" style="width: 1000px;height: 2000px;" src="http://www.autohome.com.cn"></iframe>
<script>
function changeScr() {
var inp = document.getElementById('txt1').value;
document.getElementById('ifr').src = inp;
}
</script>
</body>
</html>
iframe使用案例

#urls.py
url(r'^fake_ajax/', views.fake_ajax),
#views.py
from django.shortcuts import render,HttpResponse,redirect
import os
def fake_ajax(request):
if request.method == "GET":
return render(request,'fake_ajax.html')
else:
print(request.POST)
return HttpResponse('傳回值')
#fake_ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="f1" method="POST" action="/fake_ajax/" target="ifr">
<iframe id="ifr" name="ifr" style="display: none;"></iframe>
<input type="text" name="user">
<a onclick="submitForm();">送出</a>
</form>
<script>
function submitForm() {
document.getElementById('ifr').onload = loadIframe;
document.getElementById('f1').submit();
}
function loadIframe() {
var content = document.getElementById('ifr').contentWindow.document.body.innerText;
alert(content);
}
</script>
</body>
</html>
基于iframe的Form表單實作僞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 demo
原生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

#views.py
def index(request):
return render(request,'index.html')
# GET方式接受
def add2(request):
if request.method == "GET":
import time
time.sleep(10)
i1 = int(request.GET.get('i1'))
i2 = int(request.GET.get('i2'))
print('add2')
return HttpResponse(i1+i2)
#index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="i1">
+
<input type="text" id="i2">
=
<input type="text" id="i3">
<input type="button" onclick="add2()" value="原生 Ajax">
<script src="/static/jquery-3.2.1.js"></script>
<script>
{# 先建立一個對象#}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if(xhr.readyState ==4 ){
alert(xhr.responseText);
}
};
xhr.open('GET','/add2/?i1=12&i2=19');
xhr.send();
}
</script>
</body>
</html>
基于GET方式得原生AJAX

#views.py
def index(request):
return render(request,'index.html')
def add2(request):
# request.POST
"POST看源碼:Content-Type','application/x-www-form-urlencoded"
if request.method == "POST":
i1 = int(request.POST.get("i1"))
i2 = int(request.POST.get("i2"))
print('add2...')
return HttpResponse(i1+i2)
#index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="i1">
+
<input type="text" id="i2">
=
<input type="text" id="i3">
<input type="button" onclick="add2()" value="原生 Ajax">
<script src="/static/jquery-3.2.1.js"></script>
<script>
function add2() {
{# 先建立一個對象#}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
alert(xhr.responseText);
}
};
xhr.open('POST','/add2/');
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send("i1=12&i2=19");
}
</script>
</body>
</html>
基于POST方式得原生AJAX

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>XMLHttpRequest - Ajax請求</h1>
<input type="button" onclick="XmlGetRequest();" value="Get發送請求" />
<input type="button" onclick="XmlPostRequest();" value="Post發送請求" />
<script src="/statics/jquery-1.12.4.js"></script>
<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;
console.log(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;
console.log(data);
}
};
// 指定連接配接方式和位址----檔案方式
xhr.open('get', "/test/", true);
// 發送請求
xhr.send();
}
</script>
</body>
</html>
基于原生AJAX - Demo
jQuery Ajax
jQuery其實就是一個JavaScript的類庫,其将複雜的功能做了上層封裝,使得開發者可以在其基礎上寫更少的代碼實作更多的功能。
- jQuery 不是生産者,而是大自然搬運工。
- jQuery Ajax本質 XMLHttpRequest 或 ActiveXObject
注:2.+版本不再支援IE9以下的浏覽器

#urls.py
url(r'^index/', views.index),
#views.py
from django.shortcuts import render,HttpResponse,redirect
import os
def index(request):
return render(request,'index.html')
def add1(request):
i1 = int(request.POST.get("i1"))
i2 = int(request.POST.get("i2"))
return HttpResponse(i1 + i2)
#index.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="i1">
+
<input type="text" id="i2">
=
<input type="text" id="i3">
<input type="BUTTON" onclick="add1();" value="Query Ajax">
<script src="/static/jquery-3.2.1.js"></script>
<script>
function add1() {
$.ajax({
url: '/add1/',
type: 'POST',
data: {"i1":$("#i1").val(),"i2":$("#i2").val()},
success:function (arg) {
$("#i3").val(arg)
}
})
}
</script>
</body>
</html>
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: 載入成功時回調函數。
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="XmlSendRequest();" value='Ajax請求' />
</p>
<script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'GET',
dataType: 'text',
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
}
</script>
</body>
</html>
基于jQueryAjax - Demo
三種方式進行檔案上傳:
分别是:原生Ajax上傳檔案、jQuery Ajax上傳檔案、僞Ajax上傳檔案。

#urls.py
url(r'^upload/', views.upload),
#views.py
from django.shortcuts import render,HttpResponse,redirect
import os
def upload(request):
if request.method == "GET":
return render(request,'upload.html')
else:
print(request.POST,request.FILES)
file_obj = request.FILES.get('fafafa')
file_path = os.path.join("static",file_obj.name)
with open(file_path,'wb') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return HttpResponse(file_path)
#upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>原生Ajax上傳檔案</h1>
<input type="file" id="i1">
<a onclick="upload1()">上傳</a>
<div id="container1"></div>
<h1>jQuery Ajax上傳檔案</h1>
<input type="file" id="i2">
<a onclick="upload2()">上傳</a>
<div id="container2"></div>
<h1>僞 Ajax上傳檔案</h1>
<form id="f1" method="POST" action="/upload/" target="ifr" enctype="multipart/form-data">
<iframe id="ifr" name="ifr" style="display: none;"></iframe>
<input type="file" name="fafafa">
<a onclick="upload3()">上傳</a>
</form>
<div id="container3"></div>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function upload1() {
var formData = new FormData();
formData.append('k1','v1');
formData.append('fafafa',document.getElementById('i1').files[0]);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
var file_path = xhr.responseText;
var tag = document.createElement('img');
tag.src = "/"+file_path;
document.getElementById('container1').appendChild(tag);
}
};
xhr.open('POST','/upload/');
xhr.send(formData)
}
function upload2() {
var formData = new FormData();
formData.append('k1','v1');
formData.append('fafafa',$('#i2')[0].files[0]);
$.ajax({
url: '/upload/',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success:function (arg) {
var tag = document.createElement('img');
tag.src = "/" + arg;
$('#container2').append(tag);
}
})
}
function upload3() {
document.getElementById('ifr').onload = loadIframe;
document.getElementById('f1').submit();
}
function loadIframe() {
var content = document.getElementById('ifr').contentWindow.document.body.innerText;
var tag = document.createElement('img');
tag.src = "/"+content;
$('#container3').append(tag);
}
</script>
</body>
</html>
三種方式檔案上傳案例
跨域AJAX
由于浏覽器存在同源政策機制,同源政策阻止從一個源加載的文檔或腳本擷取或設定另一個源加載的文檔的屬性。
特别的:由于同源政策是浏覽器的限制,是以請求的發送和響應是可以進行,隻不過浏覽器不接受罷了。
浏覽器同源政策并不是對所有的請求均制約:
- 制約: XmlHttpRequest
- 不叼: img、iframe、script等具有src屬性的标簽
跨域,跨域名通路,如:http://www.c1.com 域名向 http://www.c2.com域名發送請求。
1、JSONP實作跨域請求
JSONP(JSONP - JSON with Padding是JSON的一種“使用模式”),利用script标簽的src屬性(浏覽器允許script标簽跨域)
自己寫動态建立script方式實作:

#添加windows系統hosts域名解析
#路徑 C:\Windows\System32\drivers\etc\hosts
127.0.0.1 www.s4.com
127.0.0.1 www.s5.com
#settings.py
ALLOWED_HOSTS = ['www.s5.com',] #需要在這裡添加域名不然不能通路
#urls.py
url(r'^jsonp/', views.jsonp),
#views.py
def jsonp(request):
return render(request,'jsonp.html')
#jsonp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="擷取使用者清單" onclick="getUsers();">
<ul id="user_list">
</ul>
<script>
function getUsers() {
var tag = document.createElement('script');
tag.src = "http://www.s4.com:8001/users/?funcname=bbb";
document.head.appendChild(tag);
}
function bbb(arg) {
console.log(arg)
}
</script>
</body>
</html>
WEB1

#settings.py
ALLOWED_HOSTS = ['www.s5.com',] #需要在這裡添加域名不然不能通路
#urls.py
url(r'^users/', views.users),
#views.py
import json
from django.shortcuts import render,HttpResponse,redirect
def users(request):
v = request.GET.get('funcname')
print('請求來了...')
user_list = [
'alex','eric','egon'
]
user_list_str = json.dumps(user_list)
temp = "%s(%s)" %(v,user_list_str)
print(temp)
return HttpResponse(temp)
WEB2
通過jQuery方式實作:

#添加windows系統hosts域名解析
#路徑 C:\Windows\System32\drivers\etc\hosts
127.0.0.1 www.s4.com
127.0.0.1 www.s5.com
#settings.py
ALLOWED_HOSTS = ['www.s5.com',] #需要在這裡添加域名不然不能通路
#urls.py
url(r'^jsonp/', views.jsonp),
#views.py
def jsonp(request):
return render(request,'jsonp.html')
#jsonp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="擷取使用者清單" onclick="getUsers();">
<ul id="user_list">
</ul>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function getUsers() {
$.ajax({
url: 'http://www.s4.com:8001/users/',
type: 'POST',
dataType: 'JSONP',
jsonp: 'funcname',
jsonpCallback: 'bbb'
})
}
function bbb(arg) {
console.log(arg)
}
</script>
</body>
</html>

#settings.py
ALLOWED_HOSTS = ['www.s4.com',] #需要在這裡添加域名不然不能通路
#urls.py
url(r'^users/', views.users),
#views.py
import json
from django.shortcuts import render,HttpResponse,redirect
def users(request):
v = request.GET.get('funcname')
print('請求來了...')
user_list = [
'alex','eric','egon'
]
user_list_str = json.dumps(user_list)
temp = "%s(%s)" %(v,user_list_str)
print(temp)
return HttpResponse(temp)

<!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 - Demo
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
基于cors實作AJAX請求:
a、支援跨域,簡單請求
伺服器設定響應頭:Access-Control-Allow-Origin = '域名' 或 '*'
簡單:

#urls.py
url(r'^cors/', views.cors),
#views.py
def cors(request):
return render(request,'cors.html')
#cors.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="擷取使用者清單" onclick="getUsers();">
<ul id="user_list">
</ul>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function getUsers() {
$.ajax({
url:"http://127.0.0.1:8001/new_users/",
type:"GET",
success:function (arg) {
console.log(arg);
}
})
}
</script>
</body>
</html>

#urls.py
url(r'^new_users/', views.new_users),
#views.py
def new_users(request):
user_list = [
'alex', 'eric', 'egon'
]
user_list_str = json.dumps(user_list)
obj = HttpResponse(user_list_str)
obj['Access-Control-Allow-Origin'] = "http://127.0.0.1:8000" #僅允許本地8000端口
# obj['Access-Control-Allow-Origin'] = "*" #全部允許
return obj

<!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"}')
Torando
b、支援跨域,複雜請求
由于複雜請求時,首先會發送“預檢”請求,如果“預檢”成功,則發送真實資料。
- “預檢”請求時,允許請求方式則需伺服器設定響應頭:Access-Control-Request-Method
- “預檢”請求時,允許請求頭則需伺服器設定響應頭:Access-Control-Request-Headers
- “預檢”緩存時間,伺服器設定響應頭:Access-Control-Max-Age

#urls.py
url(r'^cors/', views.cors),
#views.py
def cors(request):
return render(request,'cors.html')
#cors.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="擷取使用者清單" onclick="getUsers();">
<ul id="user_list">
</ul>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function getUsers() {
$.ajax({
url:"http://127.0.0.1:8001/new_users/",
type:"DELETE",
success:function (arg) {
console.log(arg);
}
})
}
</script>
</body>
</html>

#urls.py
url(r'^new_users/', views.new_users),
#views.py
import json
from django.shortcuts import render,HttpResponse,redirect
def new_users(request):
print(request.method)
if request.method == "OPTIONS":
print('預檢...')
obj = HttpResponse()
obj['Access-Control-Allow-Origin'] = "*"
obj['Access-Control-Allow-Methods'] = "DELETE"
return obj
obj = HttpResponse('sldkjfkdjd')
obj['Access-Control-Allow-Origin'] = "*"
return obj

<!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>

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)
Tornado
c、跨域擷取響應頭
預設擷取到的所有響應頭隻有基本資訊,如果想要擷取自定義的響應頭,則需要再伺服器端設定Access-Control-Expose-Headers。

<!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);
// 擷取響應頭
console.log(xhr.getAllResponseHeaders());
}
};
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);
// 擷取響應頭
console.log(xmlHttpRequest.getAllResponseHeaders());
}
})
}
</script>
</body>
</html>

class MainHandler(tornado.web.RequestHandler):
def put(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('xxoo', "seven")
self.set_header('bili', "daobidao")
self.set_header('Access-Control-Expose-Headers', "xxoo,bili")
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)
d、跨域傳輸cookie
在跨域請求中,預設情況下,HTTP Authentication資訊,Cookie頭以及使用者的SSL證書無論在預檢請求中或是在實際請求都是不會被發送。
如果想要發送:
- 浏覽器端:XMLHttpRequest的withCredentials為true
- 伺服器端:Access-Control-Allow-Credentials為true
- 注意:伺服器端響應的 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.withCredentials = true;
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'},
xhrFields:{withCredentials: true},
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
}
</script>
</body>
</html>

class MainHandler(tornado.web.RequestHandler):
def put(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Credentials', "true")
self.set_header('xxoo', "seven")
self.set_header('bili', "daobidao")
self.set_header('Access-Control-Expose-Headers', "xxoo,bili")
self.set_cookie('kkkkk', 'vvvvv');
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)