AJAX请求和跨域请求详解(原生JS、Jquery)

时间:2023-11-23 10:14:32

一、概述

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标签。

AJAX请求和跨域请求详解(原生JS、Jquery)

 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')