<前端技术>Ajax解析
目录:
ajax简介
对于web程序,通过浏览器接收并处理请求,然后返回结果,往往返回的是字符串(html),并由浏览器进行渲染,而一个操作需要加载所有的页面,而ajax全称为Asynchronous JavaScript and XML (异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案,可以实现请求后对局部页面进行刷新。
可以实现注册的时候检查用户是否存在,登录时提醒用户的用户名密码错误等操作。
ajax的三种实现方式
原生ajax
概述
原生的ajax通过浏览器提供的对象XMLHttpRequest进行请求的操作,像IE5,IE6的浏览器并没有,不过现在主流的浏览器中都提供该对象。
XMLHttpRequest对象主要方法
创建请求
void open(String method, String url, Boolen async)
参数介绍
- method: 请求方式(字符串类型),例如POST,GET,DELETE
- url: 要请求的地址(字符串类型)
- asyne:是否异步(布尔类型)
发送请求
void send(String body)
参数介绍
- body:要发送的数据(字符串类型)
设置请求头
void setRequestHeader(String header, String value)
在POST请求的时候需要设置请求头,而GET请求不需要
参数介绍
- header: 请求头的key(字符串类型)
- value:请求头的value(字符串类型)
获取响应头
getAllResponseHeaders()
- 返回值: 响应头数据(字符串类型)
获取响应头指定header
getResponseHeader(String header)
参数介绍
- header:响应头的key(字符串类型)
返回值
- 响应头中指定的header对应的值
终止请求
abort()
XMLHttpRequest对象主要属性
状态值
Number readyState
详细值:
- 0:未初始化,尚未调用open()方法
- 1:启动,调用了open()方法,为调用send()方法
- 2:发送,已经调用了send()方法,未接收到响应
- 3:接收,已经接收了部分响应数据
- 4:完成,已经接收了全部响应数据
当readyState的值发生改变的时候自动触发的函数(回调函数)
Function onreadystatechange
服务器返回的数据(字符串类型)
String responseText
服务器返回的数据(XML类型)
XmlDocument responseXML
状态码
Number states
状态码,例如200,404等
通过tornado实现ajax
html代码
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input id="username" type="text" name="username" />
<input id="passwd" type="password" name="passwd" />
<input type="button" value="提交" onclick="SubmitForm();" />
<script>
function SubmitForm() {
xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象
xhr.open("POST", "/login", true); //创建请求
xhr.onreadystatechange = Func; //状态值改变的回调函数
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8") //设置响应头
xhr.send("username=" + document.getElementById('username').value + ";passwd=" + document.getElementById('passwd').value) //发送请求
}
function Func() {
if(xhr.readyState == 4){ //根据状态值判断是否接收到响应数据
console.log(1)
var data = xhr.responseText; //获取响应数据
var ret_dict = JSON.parse(data);
if(ret_dict.status){
//pass
}else{
alert(ret_dict.message)
}
}
}
</script>
</body>
</html>
toanado代码
#!/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):
dic = {"status": True, "message": ""}
username = self.get_argument('username',None)
passwd = self.get_argument('passwd',None)
if username == 'why' and passwd == '123456':
pass
else:
dic['status'] = False
dic['message'] = "用户名密码错误"
import json
self.write(json.dumps(dic)) #返回字符串
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/login", LoginHandler),
], ) #加载settings
if __name__ == "__main__":
application.listen(8888) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环
如果想跨浏览器支持,可以先定义
function GetXHR(){
var xhr = null;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
然后创建对象的时候通过以下方式创建
var xhr = GetXHR();
JQuery提供的ajax实现
JQuery的2.x版本默认是不支持IE9以下的浏览器版本,如果想要支持IE5和6的话,需要使用JQuery1.x
function SubmitForm() {
$.post('/login',{'username': $('#username').val(), 'passwd': $('#passwd').val()}, function(callback){
console.log(callback);
});
}
方法解析
$.get({
url: '地址',
data: {'k1':'v1',......},
success: function('返回字符串'){
方法内容
}
})
浏览器默认返回的是字符串,需要对其返回结果进行特定格式的解析,例如Json的就需要执行JSON.parse(),不过也可以直接通过执行dataType指定返回结果的解析方式。
$.get({
url: '地址', //待载入页面的URL地址
data: {'k1':'v1',......}, //待发送 Key/value 参数。
dataType: "json" //返回内容格式,xml, json, script, text, html
success: function('返回字符串'){ //载入成功时回调函数。
方法内容
}
})
如果dataType指定为script,内部就会为其执行一个eval方法。
而还有一些方法,例如getJson()就是在get的基础上直接指定了dataType: "json",同理还有getScript()
但是这些操作最后都是调用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;
}
},
});
iframe实现伪ajax
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>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>
直接访问即可,当我们刷新页面的时候,当前时间是变动的
而当我们输入网页进行请求的时候
可以看到时间是没有进行改变的,所以是一个局部的请求,并没有重新加载所有的页面
甚至可以把页面链接过来成为自己的网站.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
margin: 0px;
}
</style>
</head>
<body>
<iframe id="iframePosition" style="width: 100%;height: 1000px" src="http://www.whysdomain.com"></iframe>
</body>
</html>
不过还是有个滑动窗口
通过ajax上传文件
tornado代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop #导入模块
import tornado.web
class IndexHandler(tornado.web.RequestHandler): #继承tornado.web.RequestHandler
def get(self): #直接访问的时候
self.render("index.html") #返回html
def post(self,*args,**kwargs):
file = self.request.files["f"]
for meta in file:
file_name = meta['filename']
with open(file_name,"wb") as up:
up.write(meta['body'])
self.render("index.html")
settings = {
'template_path': 'template', #配置模板路径
'static_path': 'static', #静态文件路径
}
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/index",IndexHandler), #当发送url请求的时候,对检查是否匹配,然后路由到对应的类的get,post等方法(路由映射)
], **settings) #加载settings
if __name__ == "__main__":
application.listen(8888) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/index" method="POST" enctype="multipart/form-data">
<input type="file" name="f">
<input type="submit" value="提交">
</form>
</body>
注意这里要加multipart/form-data
如果要指定路径,post方法可以进行一下修改
def post(self,*args,**kwargs):
file = self.request.files["f"]
for meta in file:
file_name = meta['filename']
import os
with open(os.path.join('statics','img',file_name),"wb") as up:
up.write(meta['body'])
self.render("index.html")
代码目录
通过原生ajax
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/index" method="POST" enctype="multipart/form-data">
<input type="file" id="img" name="f">
<input type="button" value="提交" onclick="UploadFile();">
</form>
<script>
function UploadFile(){
var fileObj = document.getElementById("img").files[0];
var form = new FormData();
form.append("f", fileObj);//如果有更多的其他的key,value也可以添加
var xhr = new XMLHttpRequest();
xhr.open("post","/index",true);
xhr.send(form)
}
</script>
</body>
</html>
使用JQuery的ajax提交
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/index" method="POST" enctype="multipart/form-data">
<input type="file" id="img" name="f">
<input type="button" value="提交" onclick="UploadFile2();">
</form>
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function UploadFile(){
var fileObj = document.getElementById("img").files[0];
var form = new FormData();
form.append("f", fileObj);//如果有更多的其他的key,value也可以添加
var xhr = new XMLHttpRequest();
xhr.open("post","/index",true);
xhr.send(form)
}
function UploadFile2(){
var fileObj = $("#img")[0].files[0];
var form = new FormData();
form.append("f", fileObj); //如果有更多的其他的key,value也可以添加
$.ajax({
type: 'POST',
url: '/index',
data: form,
processData: false, //JQuery不处理数据
contentType: false ,//JQuery不设置内容类型
})
}
</script>
</body>
</html>
通过伪ajax
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.hide{
display: none;
}
</style>
</head>
<body>
<form action="/index" id="my_form" method="POST" enctype="multipart/form-data">
<input type="file" id="img" name="f">
<input type="button" value="提交" onclick="UploadFile3();">
<iframe id="my_iframe" name="my_iframe" src="" class="hide"></iframe>
</form>
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function UploadFile(){
var fileObj = document.getElementById("img").files[0];
var form = new FormData();
form.append("f", fileObj);//如果有更多的其他的key,value也可以添加
var xhr = new XMLHttpRequest();
xhr.open("post","/index",true);
xhr.send(form)
}
function UploadFile2(){
var fileObj = $("#img")[0].files[0];
var form = new FormData();
form.append("f", fileObj); //如果有更多的其他的key,value也可以添加
$.ajax({
type: 'POST',
url: '/index',
data: form,
processData: false, //JQuery不处理数据
contentType: false ,//JQuery不设置内容类型
})
}
function UploadFile3(){
document.getElementById('my_iframe').onload = Testt;
document.getElementById('my_form').target = 'my_iframe';//提交到iframe
document.getElementById('my_form').submit();
}
function Testt(ths){
var t = $("#my_iframe").contents().find("body").text();
console.log(t);
}
</script>
</body>
</html>
ajax跨域请求
对于ajax请求,如果跨域名,浏览器默认是不允许的
在hosts文件中修改一下把本机127.0.0.1绑定一个域名www.why.com和www.wanghongyu.com进行模拟。
为什么会出现跨域
跨域问题来源于JavaScript的同源策略,即只有"协议+主机名+端口号(如存在)"相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。跨域问题是针对JS和ajax的,html本身没有跨域问题,比如a标签、script标签、甚至form标签(可以直接跨域发送数据并接收数据)等
主域名不同,子域名不同,端口不同,协议不同都不能机型跨域
用于发送跨域ajax请求的web server
tornado代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop #导入模块
import tornado.web
class KuayuOneHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render('kuayu.html')
settings = {
'template_path': 'template', #配置模板路径
'static_path': 'static', #静态文件路径
}
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/kuayuone",KuayuOneHandler),
], **settings) #加载settings
if __name__ == "__main__":
application.listen(8888) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="提交" onclick="DoAjax();">
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function DoAjax(){
$.ajax({
url: 'http://www.why.com:8889/kuayutwo',
type: 'POST',
data: "{'k1','v1'}",
success: function(arg){
console.log(arg);
}
})
}
</script>
</body>
</html>
用于接收跨域ajax请求的web server
tornado代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop #导入模块
import tornado.web
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.write('why kuayu2')
settings = {
'template_path': 'template', #配置模板路径
'static_path': 'static', #静态文件路径
}
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/kuayutwo",KuayuTwoHandler), #当发送url请求的时候,对检查是否匹配,然后路由到对应的类的get,post等方法(路由映射)
], **settings) #加载settings
if __name__ == "__main__":
application.listen(8889) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环
进行跨域ajax请求
用于接收ajax请求的服务器
用于发送ajax请求的服务器
当点击提交后会发送跨域的ajax请求,从www.wanghongyu.com发送到www.why.com
在console中可以看到提交失败
报错信息为:
XMLHttpRequest cannot load http://www.why.com:8889/kuayutwo. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.wanghongyu.com:8888' is therefore not allowed access.
可以看到报错是禁止跨域请求的,报错的位置是在浏览器接收到结果的时候,请求可以进行发送,并且能接收到返回的结果,由于浏览器的同源策略,不是本域名的,所以报错。
如果想进行跨域ajax请求,有两种方式,一种是以jsonp的方式实现,另一种是接收端设置响应人实现。
通过jsonp方式实现跨域ajax
对于jsonp,是使用了代码块的src属性,带有src属性的代码块都可以跨域进行请求,例如iframe,img,script等,jsonp就是使用的script
原生ajax实现
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="提交" onclick="JsonpAjax();">
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function JsonpAjax(){
var tag = document.createElement('script');
tag.src = "http://www.why.com:8889/kuayutwo";
document.head.appendChild(tag);
document.head.removeChild(tag);
}
</script>
</body>
</html>
创建一个script标签,标签中src为需要请求的网站,当执行的时候就进行了一次get请求,注意只能是get请求
然后就能看到ajax的请求结果了,刚才是使用原生的ajax实现的
JQuery实现
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="提交" onclick="JsonpAjax();">
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function JsonpAjax(){
$.ajax({
url: "http://www.why.com:8889/kuayutwo",
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallBack: 'func'
})
}
function func(dict){
console.log(dict);
}
</script>
</body>
</html>
接收跨域ajax请求的web server进行修改
tornado代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop #导入模块
import tornado.web
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('func([11,22,33]);')
def post(self, *args, **kwargs):
self.write('why kuayu2')
settings = {
'template_path': 'template', #配置模板路径
'static_path': 'static', #静态文件路径
}
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/kuayutwo",KuayuTwoHandler), #当发送url请求的时候,对检查是否匹配,然后路由到对应的类的get,post等方法(路由映射)
], **settings) #加载settings
if __name__ == "__main__":
application.listen(8889) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环
这样就实现了跨域ajax请求
不过,接收ajax请求的服务器返回的方法为func,所以发送ajax请求的服务器只能使用func方法作为回调函数。
其实在发送请求的时候callback是一个参数被传递到服务器的。
回调函数发送名作为参数
html代码
这里只是修改了回调函数的方法名
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="提交" onclick="JsonpAjax();">
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function JsonpAjax(){
$.ajax({
url: "http://www.why.com:8889/kuayutwo",
dataType: 'jsonp',
jsonpCallback: 'aaa'
})
}
function aaa(dict){
console.log(dict);
}
</script>
</body>
</html>
tornado代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop #导入模块
import tornado.web
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
callback = self.get_argument('callback')
print callback
self.write('%s([11,22,33]);' % callback)
def post(self, *args, **kwargs):
self.write('why kuayu2')
settings = {
'template_path': 'template', #配置模板路径
'static_path': 'static', #静态文件路径
}
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/kuayutwo",KuayuTwoHandler), #当发送url请求的时候,对检查是否匹配,然后路由到对应的类的get,post等方法(路由映射)
], **settings) #加载settings
if __name__ == "__main__":
application.listen(8889) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环
可以看到请求的时候是把callback当做一个参数传递给了服务端
以上是使用最多的一种方法。
通过响应头
第二种方法是需要浏览器的版本,实现的方式是在返回数据的时候加入响应头,通过cors跨域资源共享来实现。
以下代码在回到第一种方式的初始代码后的操作
还是原来的报错
XMLHttpRequest cannot load http://www.why.com:8889/kuayutwo. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.wanghongyu.com:8888' is therefore not allowed access.
可以看到报错是禁止跨域请求的,报错的位置是在浏览器接收到结果的时候,请求可以进行发送,并且能接收到返回的结果,由于浏览器的同源策略,不是本域名的,所以报错。我们在请求头中添加该参数即可。
设置响应头实现ajax跨域请求
在允许跨请求的响应头添加域名
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.write('why kuayu2')
如果过多url可以使用self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888,http://www.whysdomain.com')
,也可以用*
来允许全部。
不过,这是对于简单请求。
简单请求和非简单请求
区分条件:
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
非简单请求的跨域ajax请求
初始准备
html中由post换为put
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="提交" onclick="DoAjax();">
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function DoAjax(){
$.ajax({
url: 'http://www.why.com:8889/kuayutwo',
type: 'PUT',
data: "{'k1','v1'}",
success: function(arg){
console.log(arg);
}
})
}
</script>
</body>
</html>
tornado代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop #导入模块
import tornado.web
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.write('why kuayu2')
def put(self, *args, **kwargs):
self.write('why kuayu2')
settings = {
'template_path': 'template', #配置模板路径
'static_path': 'static', #静态文件路径
}
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/kuayutwo",KuayuTwoHandler), #当发送url请求的时候,对检查是否匹配,然后路由到对应的类的get,post等方法(路由映射)
], **settings) #加载settings
if __name__ == "__main__":
application.listen(8889) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环
可以看到
OPTIONS http://www.why.com:8889/kuayutwo 405 (Method Not Allowed)
没有options方法报错405
服务端添加options方法
tornado代码
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.write('why kuayu2')
def options(self, *args, **kwargs):
self.write('why kuayu2')
def put(self, *args, **kwargs):
self.write('why kuayu2')
再次进行跨域ajax请求
报错信息为:
XMLHttpRequest cannot load http://www.why.com:8889/kuayutwo. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.wanghongyu.com:8888' is therefore not allowed access.
还是因为跨域请求没有允许
添加option方法的允许访问域名
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.write('why kuayu2')
def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','*')
self.write('why kuayu2')
def put(self, *args, **kwargs):
self.write('why kuayu2')
报错信息
MLHttpRequest cannot load http://www.why.com:8889/kuayutwo. Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.
这是因为虽然返回了预检信息,但是在options中没有允许put方法
添加允许put方法
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.write('why kuayu2')
def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','*')
self.set_header('Access-Control-Allow-Methods','PUT')
self.write('why kuayu2')
def put(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','*')
self.write('why kuayu2')
并且这次我们先允许了put的方法的跨域ajax请求
对于自定义请求头
对于自定义的请求头进行跨域的ajax请求的时候,也是需要预检的
设置一个请求头
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="提交" onclick="DoAjax();">
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function DoAjax(){
$.ajax({
url: 'http://www.why.com:8889/kuayutwo',
type: 'PUT',
headers : {'h1':'why'},
data: "{'k1','v1'}",
success: function(arg){
console.log(arg);
}
})
}
</script>
</body>
</html>
进行跨域请求
报错信息:
XMLHttpRequest cannot load http://www.why.com:8889/kuayutwo. Request header field h1 is not allowed by Access-Control-Allow-Headers in preflight response.
这是在没有允许自定义的请求头
设置允许自定义请求头
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.write('why kuayu2')
def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','*')
self.set_header('Access-Control-Allow-Methods','PUT')
self.set_header('Access-Control-Allow-Headers','h1')
self.write('why kuayu2')
def put(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','*')
self.write('why kuayu2')
预检信息超时时间
self.set_header('Access-Control-Max-Age', 10)
设置预检的过期时间,10s内再次发送请求的时候不会进行预检。
携带cookies进行跨域ajax
ajax内要添加
xhrFields:{withCredentials: true},
而options和put中都需要加入
self.set_header('Access-Control-Allow-Credenttials','k1')
和
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
注意这个Access-Control-Allow-Origin一定不能是*,否则会报
报错信息
XMLHttpRequest cannot load http://www.why.com:8889/kuayutwo. Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://www.wanghongyu.com:8888' is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
没有允许Access-Control-Allow-Credenttials的话
报错信息
XMLHttpRequest cannot load http://www.why.com:8889/kuayutwo. Response to preflight request doesn't pass access control check: Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'http://www.wanghongyu.com:8888' is therefore not allowed access.
以下是成功进行请求的代码
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="提交" onclick="DoAjax();">
<script src="http://image.whysdomain.com/static/jquery-1.8.2.js"></script>
<script>
function DoAjax(){
$.ajax({
url: 'http://www.why.com:8889/kuayutwo',
type: 'PUT',
headers : {'h1':'why'},
data: "{'k1','v1'}",
xhrFields:{withCredentials: true},
success: function(arg){
console.log(arg);
}
})
}
</script>
</body>
</html>
tornado代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop #导入模块
import tornado.web
class KuayuTwoHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write('why kuayu2')
def post(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.write('why kuayu2')
def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.set_header('Access-Control-Allow-Methods','PUT')
self.set_header('Access-Control-Allow-Headers','h1')
self.set_header('Access-Control-Allow-Credentials','k1')
self.write('why kuayu2')
def put(self, *args, **kwargs):
self.set_cookie('k1','wanghongyu')
self.set_header('Access-Control-Allow-Origin','http://www.wanghongyu.com:8888')
self.set_header('Access-Control-Allow-Credentials','k1')
self.write('why kuayu2')
settings = {
'template_path': 'template', #配置模板路径
'static_path': 'static', #静态文件路径
}
application = tornado.web.Application([ #创建tornado.web.Application对象
(r"/kuayutwo",KuayuTwoHandler), #当发送url请求的时候,对检查是否匹配,然后路由到对应的类的get,post等方法(路由映射)
], **settings) #加载settings
if __name__ == "__main__":
application.listen(8889) #创建一个socket
tornado.ioloop.IOLoop.instance().start() #使用epoll,IO多路复用循环