tornado 框架二(cookie session ajax 表单上传)
1.cookie 是在浏览器端保存的键值对 ,特性:每次http请求携带cookie
tornado 在后台设置
self.cookies
self.set_cookie('k','v',过期时间)
self.get_cookie('')
在前台javascript设置
document.cookie
document.cookie['k']
document.cookie.split(';')
document.cookie = "k2=v2;path=/;"
自定义函数 过期时间要转换为UTC时间
function setCookie(name,value,expires){
var current_date = new Date();
current_date.setSecondes(current_date.getSeconds()+5);
document.cookie = name + "=" + value + ";expires=" + current_date.toUTCString();
}
jquery 设置cookie
下载jquery cookie 插件
$.cookie('k','v',{path:'/',domin:'',expires:})
2.cookie 安全验证
使用
self.set_secure_cookie()
self.get_secure_cookie()
setting 里面设置
'cookie_secret':'abcdefg'
3.签名的Cookie流程:
- 写cookie过程:
- 将值进行base64加密
- 对除值以外的内容进行签名,哈希算法(无法逆向解析)
- 拼接 签名 + 加密值
- 读cookie过程:
- 读取
签名 + 加密值 - 对签名进行验证
- base64解密,获取值内容
k1= v1
v1 =base64(v1)
v1|v1+当前时间戳 +自定义字符串
k1 = v1|加密字符串|当前时间戳
4.自定义 session 加密签名实例
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import tornado.web import tornado.ioloop import hashlib import time contain = {} class Session: def __init__(self,handler): self.handler = handler # 传递过来的handler 用于获取cookie self.random_str = None # 防止多次设置,产生多个随机字符串 def __get_random_str(self): # 获取随机的字符串 hmd5 = hashlib.md5() hmd5.update(bytes(str(time.time()),encoding='utf-8')) random_str = hmd5.hexdigest() return random_str def set_value(self,key,value): if not self.random_str: # 如果 第一次 set_value random_str = self.handler.get_cookie('abcdefg') #获取cookie if not random_str: #如果客户端没有 cookie random_str = self.__get_random_str() # 生成随机字符串 contain[random_str] = {} #创建一个以随机字符串为key 的 值为空的字典 else: #如果客户端有 cookie ,而服务器没有,服务器重启 if random_str in contain.keys(): pass else:#服务器没有随机字符串 random_str = self.__get_random_str() contain[random_str] = {} self.random_str = random_str #设置当前用户的属性 必须使用 self.random_str ,使用 random_str 第二次 set_value时,会出现举报变量的错误 contain[self.random_str][key]=value #设置cookie self.handler.set_secure_cookie('abcdefg',self.random_str) def get_value(self,key): #获取客户端cookie random_str = self.handler.get_secure_cookie('abcdefg') # get_secure_cookie 获得是字节码,需要装换 random_str = str(random_str,encoding='utf-8') if not random_str: # 客户端没有cookie return None current_user_info = contain.get(random_str,None) #获取服务端当前用户的属性 if not current_user_info: # 服务端当前用户没有设置属性 return None value = current_user_info.get(key,None) # 获取当前用户key 对应的值 return value class IndexHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): if self.get_argument('username',None) in ['abc','bcd']: s = Session(self) # 传递 handler s.set_value('is_login',True) s.set_value('username',self.get_argument('username')) else: self.write('请登录') class ManageHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): s = Session(self) val = s.get_value('is_login') if val: self.write('成功'+s.get_value('username')) else: self.write('失败') setting = { 'static_path':'static', 'template_path':'view', 'cookie_secret':'123456' } application = tornado.web.Application([ (r'/index',IndexHandler), (r'/manage',ManageHandler), ],**setting) if __name__ == '__main__': application.listen('8080') tornado.ioloop.IOLoop.instance().start()
自定义 session 修订:
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import tornado.web import tornado.ioloop import hashlib import time contain = {} class Session: def __init__(self,handler): self.handler = handler # 传递过来的handler 用于获取cookie self.random_str = None # 防止多次设置,产生多个随机字符串 def __get_random_str(self): # 获取随机的字符串 hmd5 = hashlib.md5() hmd5.update(bytes(str(time.time()),encoding='utf-8')) random_str = hmd5.hexdigest() return random_str def __setitem__(self,key,value): if not self.random_str: # 如果 第一次 set_value random_str = self.handler.get_cookie('abcdefg') #获取cookie if not random_str: #如果客户端没有 cookie random_str = self.__get_random_str() # 生成随机字符串 contain[random_str] = {} #创建一个以随机字符串为key 的 值为空的字典 else: #如果客户端有 cookie ,而服务器没有,服务器重启 if random_str in contain.keys(): pass else:#服务器没有随机字符串 random_str = self.__get_random_str() contain[random_str] = {} self.random_str = random_str #设置当前用户的属性 必须使用 self.random_str ,使用 random_str 第二次 set_value时,会出现举报变量的错误 contain[self.random_str][key]=value #设置cookie self.handler.set_secure_cookie('abcdefg',self.random_str) def __getitem__(self,key): #获取客户端cookie random_str = self.handler.get_secure_cookie('abcdefg') # get_secure_cookie 获得是字节码,需要装换 random_str = str(random_str,encoding='utf-8') if not random_str: # 客户端没有cookie return None current_user_info = contain.get(random_str,None) #获取服务端当前用户的属性 if not current_user_info: # 服务端当前用户没有设置属性 return None value = current_user_info.get(key,None) # 获取当前用户key 对应的值 return value class BaseHandler(tornado.web.RequestHandler): #钩子函数,get post 方法之前 都会执行此方法 def initialize(self): self.session = Session(self) # 传递 handler class IndexHandler(BaseHandler): def get(self, *args, **kwargs): if self.get_argument('username',None) in ['abc','bcd']: self.session['is_login']=True self.session['username']=self.get_argument('username') else: self.write('请登录') class ManageHandler(BaseHandler): def get(self, *args, **kwargs): val = self.session['is_login'] if val: self.write('成功'+self.session['username']) else: self.write('失败') setting = { 'static_path':'static', 'template_path':'view', 'cookie_secret':'123456' } application = tornado.web.Application([ (r'/index',IndexHandler), (r'/manage',ManageHandler), ],**setting) if __name__ == '__main__': application.listen('8080') tornado.ioloop.IOLoop.instance().start()
5.基于 session 的图片验证码
1. 先安装图像处理模块 pip3 install pillow 2.导入源码check_code.py Monaco.ttf 两个文件
启动文件:run.py
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import tornado.web import tornado.ioloop import hashlib import time import io import check_code contain = {} class Session: def __init__(self,handler): self.handler = handler # 传递过来的handler 用于获取cookie self.random_str = None # 防止多次设置,产生多个随机字符串 def __get_random_str(self): # 获取随机的字符串 hmd5 = hashlib.md5() hmd5.update(bytes(str(time.time()),encoding='utf-8')) random_str = hmd5.hexdigest() return random_str def __setitem__(self,key,value): if not self.random_str: # 如果 第一次 set_value random_str = self.handler.get_cookie('abcdefg') #获取cookie if not random_str: #如果客户端没有 cookie random_str = self.__get_random_str() # 生成随机字符串 contain[random_str] = {} #创建一个以随机字符串为key 的 值为空的字典 else: #如果客户端有 cookie ,而服务器没有,服务器重启 if random_str in contain.keys(): pass else:#服务器没有随机字符串 random_str = self.__get_random_str() contain[random_str] = {} self.random_str = random_str #设置当前用户的属性 必须使用 self.random_str ,使用 random_str 第二次 set_value时,会出现举报变量的错误 contain[self.random_str][key]=value #设置cookie self.handler.set_secure_cookie('abcdefg',self.random_str) def __getitem__(self,key): #获取客户端cookie random_str = self.handler.get_secure_cookie('abcdefg') # get_secure_cookie 获得是字节码,需要装换 random_str = str(random_str,encoding='utf-8') if not random_str: # 客户端没有cookie return None current_user_info = contain.get(random_str,None) #获取服务端当前用户的属性 if not current_user_info: # 服务端当前用户没有设置属性 return None value = current_user_info.get(key,None) # 获取当前用户key 对应的值 return value class BaseHandler(tornado.web.RequestHandler): #钩子函数,get post 方法之前 都会执行此方法 def initialize(self): self.session = Session(self) # 传递 handler class IndexHandler(BaseHandler): def get(self, *args, **kwargs): if self.get_argument('username',None) in ['abc','bcd']: self.session['is_login']=True self.session['username']=self.get_argument('username') else: self.write('请登录') class ManageHandler(BaseHandler): def get(self, *args, **kwargs): val = self.session['is_login'] if val: self.write('成功'+self.session['username']) else: self.write('失败') class LoginHandler(BaseHandler): def get(self, *args, **kwargs): self.render('login.html',state = "") def post(self, *args, **kwargs): text_code = self.get_argument('code') img_code = self.session["CheckCode"] if text_code.upper() == img_code.upper(): self.write('验证码正确') else: self.render('login.html', state='验证码失败') class CheckCodeHandler(BaseHandler): def get(self, *args, **kwargs): mstream = io.BytesIO() #创建图片,写入验证码 img, code = check_code.create_validate_code() #将图片对象写入 mstream img.save(mstream, "GIF") self.session["CheckCode"] = code self.write(mstream.getvalue()) setting = { 'static_path':'static', 'template_path':'view', 'cookie_secret':'123456' } application = tornado.web.Application([ (r'/index',IndexHandler), (r'/manage',ManageHandler), (r'/login',LoginHandler), (r'/checkcode',CheckCodeHandler), ],**setting) if __name__ == '__main__': application.listen('8080') tornado.ioloop.IOLoop.instance().start()
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login" method="post"> <p><input type="text" placeholder="用户名"></p> <p><input type="text" placeholder="密码"></p> <p><input type="text" placeholder="验证码" name="code"><img id="imgCode" src="/checkcode" onclick="ChangeCode();"><span style="color: red">{{state}}</span></p> <p><input type="submit" value="提交"></p> </form> <script> // 点击图片 改变验证码 function ChangeCode() { var code = document.getElementById('imgCode'); code.src +='?'; } </script> </body> </html>
6.CSRF 跨站请求伪造
配置使用
class CsrfHandler(BaseHandler): def get(self, *args, **kwargs): self.render('csrf.html') def post(self, *args, **kwargs): self.write('csrf.post') setting = { 'static_path':'static', 'template_path':'view', 'cookie_secret':'123456', 'xsrf_cookies':True, } application = tornado.web.Application([ (r'/index',IndexHandler), (r'/manage',ManageHandler), (r'/login',LoginHandler), (r'/checkcode',CheckCodeHandler), (r'/csrf',CsrfHandler), ],**setting)
<form action="/csrf" method="post"> {% raw xsrf_form_html()%} <p><input type="submit" value="提交"></p> </form>
基于ajax 的跨站请求伪造
<body> <!--<form action="/csrf" method="post">--> <!--{% raw xsrf_form_html()%}--> <!--<p><input type="submit" value="提交"></p>--> <!--</form>--> <p><input type="button" value="提交" onclick="ajaxCsrf();"></p> <script> function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined ; } function ajaxCsrf() { var nid = getCookie("_xsrf"); $.post({ url:'/csrf', data:{'k1':'v1','_xsrf':nid}, success:function (callback) { console.log(callback); } }); } </script>
7.ajax 异步+javascript+html ,异步+javascript+json
偷偷的完成局部页面的刷新
1)利用iframe实现 伪ajax
<!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> <iframe id="iframePosition" style="width: 500px;height: 500px"></iframe> </div> <script> window.onload= function () { var date = new Date(); document.getElementById('currentTime').innerText = date.getTime(); } function loadPage() { var url = document.getElementById('url').value; document.getElementById('iframePosition').src = url; } </script> </body> </html>
2)原生的ajax,get方式传递值在URL后面+?+data ,post方式传递值 send(data)
javascript:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <input type="button" value="get/ajax" onclick="GetAjax();"></div> <div> <input type="button" value="post/ajax" onclick="PostAjax();"></div> <script> function GetXHR() { var xhr = null; if(XMLHttpRequest){ xhr = new XMLHttpRequest(); }else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr } function GetAjax() { var data = 'a=123;b=456'; // 创建可兼容的xhr对象 var xhr = GetXHR(); // 设置回调函数 xhr.onreadystatechange = function () { if(xhr.readyState==4){ //收到全部响应数据,执行以下操作 console.log(xhr.responseText) } } //指定连接方式,地址等 xhr.open('get','/testajax'+'?'+data,true); // get 方式传递数据 //发送请求 xhr.send(); } function PostAjax() { var data = 'a=123;b=456'; // 创建可兼容的xhr对象 var xhr = GetXHR(); // 设置回调函数 xhr.onreadystatechange = function () { if(xhr.readyState==4){ //收到全部响应数据,执行以下操作 console.log(xhr.responseText) } } //指定连接方式,地址等 xhr.open('post','/testajax',true); //设置请求头 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); //发送请求 xhr.send(data); // post方式传递数据 } </script> </body> </html>
run.py
class TestAjaxHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): print(self.get_argument('a'),self.get_argument('b')) self.render('rawajax.html') # self.write('hell0') def post(self, *args, **kwargs): print(self.get_argument('a'), self.get_argument('b')) self.write('hello')
3)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 方法列表
使用实例
class TestAjaxHandler(tornado.web.RequestHandler): def post(self, *args, **kwargs): print(self.get_argument('a'), self.get_argument('b')) data = '{"hello":"sb"}' # 内双外单 self.write(data)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="{{static_url('jquery-3.2.1.js')}}"></script> </head> <body> <div><input type="button" value="jquery/ajax" onclick="JqueryAjax();"></div> <script> function JqueryAjax() { $.ajax({ url:'/testajax', type:'post', data: 'a=123;b=456', dataType:'json', success:function (data) { console.log(data); } }) } </script> </body> </html>
4)form表单文件上传,多选框
run.py
file_list = [] class FormHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.render('form.html',FileList = file_list) def post(self, *args, **kwargs): print(self.get_arguments('aaa')) # checkbox 使用 get_arguments #上传文件处理 file_metas = self.request.files["bbb"] # 文件信息字典 file_path ='static/file' for meta in file_metas: file_name = meta['filename'] file_list.append(file_name) with open(os.path.join(file_path,file_name), 'wb') as up: up.write(meta['body']) self.redirect('/form')
form.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <ul> {% for i in FileList%} <li><img style="width: 50px;height: 50px" src="static/file/{{i}}"></li> {% end %} </ul> </div> <form action="/form" method="post" enctype="multipart/form-data"> <p> <input type="checkbox" name="aaa" value="1">吃 <input type="checkbox" name="aaa" value="2">喝 <input type="checkbox" name="aaa" value="3">玩 </p> <p><input type="file" name="bbb"></p> <p><input type="submit" value="提交"></p> </form> </body> </html>
ajax 实现文件上传,后台代码不变
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <input type="file" id="f1"> <input type="button" value="ajax提交" onclick="ajax_file_up();"> <input type="button" value="jquery ajax提交" onclick="jquery_ajax_file_up();"> </div> <script src="{{static_url('jquery-3.2.1.js')}}"></script> <script> // 原生的ajax function ajax_file_up() { file_obj = document.getElementById('f1').files[0]; var form = new FormData(); form.append('aaa',1); form.append('aaa',2); form.append('bbb',file_obj); var xhr = new XMLHttpRequest(); xhr.open('post','/form',true); xhr.send(form); } //jquery ajax function jquery_ajax_file_up() { file_obj = $('#f1')[0].files[0]; var form = new FormData(); form.append('aaa',1); form.append('aaa',2); form.append('bbb',file_obj); $.ajax({ type:'post', url:'/form', data:form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success:function (da) { console.log(da); } }) } </script> </body> </html>
iframe 实现上传 (new FormData() IE浏览器不支持时使用)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form id="form" action="/form" method="post" enctype="multipart/form-data"> <p> <input type="checkbox" name="aaa" value="1">吃 <input type="checkbox" name="aaa" value="2">喝 <input type="checkbox" name="aaa" value="3">玩 </p> <p><input type="file" name="bbb"></p> <p><input type="button" value="上传" onclick="redirect();"></p> <p><iframe id="my_iframe" name="myiframe" style="display: none"></iframe></p> </form> <script src="{{static_url('jquery-3.2.1.js')}}"></script> <script> function redirect() { document.getElementById('my_iframe').onload = handleresponse; document.getElementById('form').target = 'myiframe'; document.getElementById('form').submit(); } function handleresponse() { var res = $("#my_iframe").contents().find('body').text(); console.log(res); } </script> </body> </html>
8.浏览器的同源策略
支持跨域:
<script src='www.google.com/xxx.js'>
<img src='www.baidu.com/xxx.jpg'>
<iframe src='www.sina.com'>
不支持跨域:
ajax
....
突破的方法一: jsonp实现跨域请求 只能是GET请求
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p><input type="button" value="jsonp1" onclick="jsonp1();"></p> <p><input type="button" value="jsonp2" onclick="jsonp2();"></p> <script src="static/jquery-3.2.1.js"></script> <script> // jsonp 跨域请求的本质 function jsonp1() { //创建 script 标签 var tag =document.createElement('script'); //设置 script 标签 src 的属性 tag.src = 'http://www.baidu.com/XXX'; // 在文档的头部添加script标签 document.head.appendChild(tag); // 在文档的头部移除script标签 document.head.removeChild(tag); } // 服务器可以返回 字符串,函数 // ajax jsonp 中使用的的就是上述的方法 function jsonp2() { $.ajax({ url:'http://www.baidu.com/XXX', type:'get', dateType:'jsonp', success:function (data, statusText, xmlHttpRequest) { console.log(data); }, jsonp:'callback', // 设置这个属性后,将服务器的函数设置为 func ,没有设置这个属性,jsonpCallBack的函数名与服务器返回函数名一致 jsonpCallBack:'func', // 服务器返回一个func 函数 (self.write('func(123)')) }); } function func(arg) { console.log(arg); } </script> </body> </html>
服务器让别人可以自定义函数进行跨域请求:
callback =self.get_argument('callback')
self.write('%s([11,22,33])' % callback)
原生的可以这样设置: tag.src = 'http://www.baidu.com/XXX?callback=myfunc';
ajax jsonp 可以这样设置: jsonp:'callback', jsonpCallBack:'myfunc'
突破方法二:跨域资源共享(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
a、支持跨域,简单请求
服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
客户端:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="ajax_corf" onclick="AjaxCorf();"> <script src="static/jquery-3.2.1.js"></script> <script> function AjaxCorf() { $.ajax({ url:'http://www.server.com:8008/index', type:'get', success:function (data) { console.log(data); } }); } </script> </body> </html>
服务端:py
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): #设置一个或者多个 允许跨域域名 self.set_header('Access-Control-Allow-Origin','http://www.client1.com:8001,http://www.client2.com:8001') # 所有域名均可访问 # self.set_header('Access-Control-Allow-Origin', '*') self.write('server get') def post(self, *args, **kwargs): pass setting = { 'template_path':'template', 'static_path':'static', } application = tornado.web.Application([ (r"/index", IndexHandler), ],**setting) if __name__ == "__main__": application.listen(8008) tornado.ioloop.IOLoop.instance().start()
b、支持跨域,复杂请求
由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。
- “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Allow-Method
- “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Allow-Headers
- “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
客户端:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="ajax_corf" onclick="AjaxCorf();"> <script src="static/jquery-3.2.1.js"></script> <script> function AjaxCorf() { $.ajax({ url:'http://www.server.com:8008/index', type:'put', headers:{'k1':'v1'}, success:function (data) { console.log(data); } }); } </script> </body> </html>
服务端:py
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): #设置一个或者多个 允许跨域域名 self.set_header('Access-Control-Allow-Origin','http://www.zzy.com:8001') # 所有域名均可访问 # self.set_header('Access-Control-Allow-Origin', '*') self.write('server get') def post(self, *args, **kwargs): pass def options(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', 'http://www.zzy.com:8001') self.set_header('Access-Control-Allow-Methods','PUT,DELETE') #必须要大写 ,没*的写法 self.set_header('Access-Control-Allow-Headers', "k1,k2") # 允许自定义请求头 self.set_header('Access-Control-Max-Age', 10) #预检超时时间 def put(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', 'http://www.client.com:8001') self.write('server put') setting = { 'template_path':'template', 'static_path':'static', } application = tornado.web.Application([ (r"/index", IndexHandler), ],**setting) if __name__ == "__main__": application.listen(8008) tornado.ioloop.IOLoop.instance().start()
c、跨域获取响应头
默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers。
客户端:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="ajax_corf" onclick="AjaxCorf();"> <script src="static/jquery-3.2.1.js"></script> <script> function AjaxCorf() { $.ajax({ url:'http://www.server.com:8008/index', type:'put', headers:{'k1':'v1'}, success:function (data, statusText, xmlHttpRequest) { console.log(data); //获取响应头 console.log(xmlHttpRequest.getAllResponseHeaders()) } }); } </script> </body> </html>
服务端:py
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): #设置一个或者多个 允许跨域域名 self.set_header('Access-Control-Allow-Origin','http://www.zzy.com:8001') # 所有域名均可访问 # self.set_header('Access-Control-Allow-Origin', '*') self.write('server get') def post(self, *args, **kwargs): pass def options(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', 'http://www.client.com:8001') self.set_header('Access-Control-Allow-Methods','PUT,DELETE') #必须要大写 ,没*的写法 self.set_header('Access-Control-Allow-Headers', "k1,k2") # 允许自定义请求头 self.set_header('Access-Control-Max-Age', 10) #预检超时时间 def put(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', 'http://www.zzy.com:8001') # 设置响应头 self.set_header('sb','12345') self.set_header('hb','56789') self.set_header('Access-Control-Expose-Headers', "sb,hb") self.write('server put') setting = { 'template_path':'template', 'static_path':'static', } application = tornado.web.Application([ (r"/index", IndexHandler), ],**setting) if __name__ == "__main__": application.listen(8008) tornado.ioloop.IOLoop.instance().start()
d、跨域传输cookie
在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。
如果想要发送:
- 浏览器端:XMLHttpRequest的withCredentials为true
- 服务器端:Access-Control-Allow-Credentials为true
- 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
客户端:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="ajax_corf" onclick="AjaxCorf();"> <script src="static/jquery-3.2.1.js"></script> <script> function AjaxCorf() { $.ajax({ url:'http://www.server.com:8008/index', type:'put', headers:{'k1':'v1'}, xhrFields:{withCredentials: true}, success:function (data, statusText, xmlHttpRequest) { console.log(data); //获取响应头 console.log(xmlHttpRequest.getAllResponseHeaders()); } }); } </script> </body> </html>
服务端:py
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): #设置一个或者多个 允许跨域域名 self.set_header('Access-Control-Allow-Origin','http://www.zzy.com:8001') # 所有域名均可访问 # self.set_header('Access-Control-Allow-Origin', '*') self.write('server get') def post(self, *args, **kwargs): pass def options(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', 'http://www.zzy.com:8001') self.set_header('Access-Control-Allow-Methods','PUT,DELETE') #必须要大写 ,没*的写法 self.set_header('Access-Control-Allow-Headers', "k1,k2") # 允许自定义请求头 self.set_header('Access-Control-Max-Age', 10) #预检超时时间 self.set_header('Access-Control-Allow-Credentials', "true") def put(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', 'http://www.zzy.com:8001') self.set_header('Access-Control-Allow-Credentials', "true") print(self.cookies) self.set_cookie('abc','def') # 设置响应头 self.set_header('sb','12345') self.set_header('hb','56789') self.set_header('Access-Control-Expose-Headers', "sb,hb") self.write('server put') setting = { 'template_path':'template', 'static_path':'static', } application = tornado.web.Application([ (r"/index", IndexHandler), ],**setting) if __name__ == "__main__": application.listen(8008) tornado.ioloop.IOLoop.instance().start()

浙公网安备 33010602011771号