初识 Tornado :javascript
tornado web server 是使用python编写出来的一个轻量级、高可伸缩性和非阻塞IO的Web服务器软件,其特色是采用epoll非阻塞IO,相应快速,可处理数千并发链接,特别适用于实时的Web服务。css
概述:html
Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具 和优化。前端
Tornado 和如今的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,并且速度至关快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒能够处理数以千计的链接,这意味着对于实时 Web 服务来讲,Tornado 是一个理想的 Web 框架。咱们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每个活动用户都会保持着一个服务器链接。(关于如何扩容 服务器,以处理数以千计的客户端的链接的问题,请参阅 C10K problem。)java
下载安装:python
pip3 install tornado
源码安装
https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz
快速上手:jquery
import tornado.ioloop 首先导入模块 import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/index", MainHandler), #路由映射(路由系统) ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
执行过程:git
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): # self.render("s1.html") #render方法,表示会自动找到文件并打开,返回给你 #render找的时候默认从当前的目录下面去找,若是想让其从别的地方找,咱们就能够 #为其作一个settings配置(也能够把绝对路径写上去), self.write("Hello, world") settings={ #若是想让配置文件生效,须要在下面application后面加一个**settings "tempalte_path":"xxx", #模板路径的匹配,其中xxx为放HTML的文件夹 "static_path":"xxx" #静态文件的配置(静态文件就是css和JavaScript),其中xxx为存放静态文件的文件夹 } #路由映射(路由系统) application = tornado.web.Application([ (r"/index", MainHandler), #检测用户的url是否匹配,若是匹配则,执行其后面类中的莫一种方法 #同一个url以不一样的方式访问,执行不一样的方法 ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
2、路由系统 (application)github
路由系统其实就是 url 和 类 的对应关系,这里不一样于其余框架,其余不少框架均是 url 对应 函数,Tornado中每一个url对应的是一个类。web
application=tornado.web.Application([
(r'/index',MainHandler)
],**settings)
内部在执行的时候执行了两个方法__init__方法和self.add_handlers(".*$", handlers)方法{源码后期解析Tornado时补充}
这个add_handlers默认传输的".*$" 就是www,他内部生成的路由映射的时候至关于(二级域名的方式)下图:
咱们能够经过application.add_handlers,添加一个“shuaige.com”,他会生成一个相似下面的对应关系shuaige.*
若是匹配的是shuaige他会去"shuaige"里去找对应关系,若是没有匹配默认就去.*,他这个就相似Django中的URL分类!~~
application = tornado.web.Application([ (r"/index", MainHandler), ]) application.add_handlers("shuaige.com",([ (r"/index", MainHandler), ]) )
路由系统其实就是 url 和 类 的对应关系,这里不一样于其余框架,其余不少框架均是 url 对应 函数,Tornado中每一个url对应的是一个类。
#!/usr/bin/env python #-*- coding:utf-8 -*- __author__ = 'luotianshuai' import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") class Shuaige(tornado.web.RedirectHandler): def get(self): self.write("This is shuaige web site,hello!") application = tornado.web.Application([ (r"/index", MainHandler), ]) application.add_handlers("shuaige.com",([ #二级路由 (r"/index", Shuaige), ]) ) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
模板:
Tornao中的模板语言和django中相似,模板引擎将模板文件载入内存,而后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。
Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {%
和 %}
包起来的 例如 {% if len(items) > 2 %}
。表达语句是使用 {{
和 }}
包起来的,例如 {{ items[0] }}
。
控制语句和对应的 Python 语句的格式基本彻底相同。咱们支持 if
、for
、while
和 try
,这些语句逻辑结束的位置须要用 {% end %}
作标记。还经过 extends
和 block
语句实现了模板继承。这些在 template
模块 的代码文档中有着详细的描述。
注:在使用模板前须要在setting中设置模板路径:"template_path" : "views"
settings = { 'template_path':'views', #设置模板路径,HTML文件放置views文件夹中 'static_path':'static', # 设置静态模板路径,css,JS,Jquery等静态文件放置static文件夹中 'static_url_prefix': '/sss/', #导入时候须要加上/sss/,例如<script src="/sss/jquery-1.9.1.min.js"></script> 本身去找该js文件 'cookie_secret': "asdasd", #cookie生成秘钥时候需提早生成随机字符串,须要在这里进行渲染 'xsrf_cokkies':True, #容许CSRF使用 } application = tornado.web.Application([ (r'/index',IndexHandler), # 路由映射 路由系统 ],**settings)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .pg-header{ height: 48px; background-color: darkcyan; } .pg-footer{ height: 100px; background-color:beige; } </style> </head> <body> <div class="pg-header"> </div> <div class="pg-contet"> {% block body %} {% end %} </div> <div class="pg-footer">AAAAAAAAAA</div> <script src="{{static_url('js/jquery-1.8.2.min.js')}}"></script> {% block js %} {% end %} </body> </html>
{% extends '../master/layout.html'%} {% block body %} <h1>Index</h1> {% include "../include/form.html" %} {% end %} {% block js %} {% end %}
模板中for循环的语法
{% extends '../master/layout.html'%} {% block body %} <h1>Fuck</h1> {% include "../include/form.html" %} {% include "../include/form.html" %} {% include "../include/form.html" %} {% include "../include/form.html" %} {% end %}
<form action="/"> <input type="text"/> <input type="submit"/> </form> <ul> {% for item in list_info %} <li>{{item}}</li> {% end %} </ul>index
在模板中默认提供了一些函数、字段、类以供模板使用: escape: tornado.escape.xhtml_escape 的別名 xhtml_escape: tornado.escape.xhtml_escape 的別名 url_escape: tornado.escape.url_escape 的別名 json_encode: tornado.escape.json_encode 的別名 squeeze: tornado.escape.squeeze 的別名 linkify: tornado.escape.linkify 的別名 datetime: Python 的 datetime 模组 handler: 当前的 RequestHandler 对象 request: handler.request 的別名 current_user: handler.current_user 的別名 locale: handler.locale 的別名 _: handler.locale.translate 的別名 static_url: for handler.static_url 的別名 xsrf_form_html: handler.xsrf_form_html 的別名
分享一个先后端交互实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="sss/commons.css" > </head> <body> <h1>提交数据</h1> <form method="get" action="/index"> <input type="text" name="xxx" /> <input type="submit" value="提交" /> </form> <h1>展现内容</h1> <h3>{{npm}}</h3> <h3>{{ func(npm) }}</h3> {% module custom(123) %} <ul> {% for item in xxxooo %} {% if item == "alex" %} <li style="color: red">{{item}}</li> {% else %} <li>{{item}}</li> {% end %} {% end %} </ul> <script src="/sss/oldboy.js"></script> </body> </html>
#!/usr/bin/env python #-*- coding:utf-8 -*- import tornado.ioloop import tornado.web import uimethod as mt import uimodule as md INPUTS_LIST = ['alex'] class MainHandler(tornado.web.RequestHandler): def get(self): name = self.get_argument("xxx",None) if name: INPUTS_LIST.append(name) self.render('s1.html',npm="NPM888",xxxooo = INPUTS_LIST) # def post(self,*args,**kwargs): # name = self.get_argument("xxx",None) # INPUTS_LIST.append(name) # self.render('s1.html',npm="NPM888",xxxooo = INPUTS_LIST) settings={ 'template_path':'tpl', 'static_path':'static', 'static_url_prefix':'/sss/', 'ui_methods':mt, 'ui_modules':md } application=tornado.web.Application([ (r'/index',MainHandler) ],**settings) if __name__ == '__main__': application.listen(8888) tornado.ioloop.IOLoop.instance().start()
模板语言有三类:
一、{{npm}}-------------self.render("s1.html",npm = "NPM888")
二、代码块的方式
{% for item in xxxooo %} ---- self.render('s1.html',xxxooo = INPUTS_LIST)
{% if item == "alex" %}
<li style="color: red">{{item}}</li>
{% else %}
<li>{{item}}</li>
{% end %}
{% end %}
三、自定义
def func(self,arg):
return "12345"
#!/usr/bin/env python # -*- coding:utf-8 -*- from tornado.web import UIModule from tornado import escape class custom(UIModule): def render(self, *args, **kwargs): return escape.xhtml_escape('<h1>哈哈哈</h1>')
cookie
Cookie是当你浏览某网站时,网站存储在你机器上的一个小文本文件,它记录了你的用户ID,密码、浏览过的网页、停留的时间等信息,当你再次来到该网站时,网站经过读取Cookie,得知你的相关信息,就能够作出相应的动做,如在页面显示欢迎你的标语,或者让你不用输入ID、密码就直接登陆等。
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): print(self.cookies) #获取http请求中携带的浏览器中的全部cookie print(self.get_cookie("k1")) # 获取浏览器中的cooki self.set_cookie('k1','111') #为浏览器设置cookie self.render('index.html') settings = { 'template_path':'views', 'static_path':'static' } application = tornado.web.Application([ (r'/index',IndexHandler), ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> function setCookie(name,value,expires) { var current_date = new Date(); current_date.setSeconds(current_date.getSeconds()+5); document.cookie = name + '='+ value +';expires='+ current_date.toUTCString(); } </script> </body> </html>
二、加密cookie(签名)
Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登录用户的 id 之类的信息,你须要对 cookie 做签名以防止伪造。Tornado 经过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你须要在建立应用时提供一个密钥,名字为 cookie_secret。 你能够把它做为一个关键词参数传入应用的设置中
签名Cookie的本质是:
写cookie过程:
v1 = base64(v1)
k1 = v1 | 加密串(md5(v1+时间戳+自定义字符串)) | 时间戳
读cookie过程:
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web import hashlib import time xin = {} #建立一个空字典 class IndexHandler(tornado.web.RequestHandler): def get(self): if self.get_argument('u',None) in['kai','xin']: obj = hashlib.md5() obj.update(bytes(str(time.time()),encoding="utf-8")) random_str = obj.hexdigest() xin[random_str] = {} xin[random_str]['k1']=123 xin[random_str]['k2']=self.get_argument('u',None)+'parents' xin[random_str]['is_login']=True self.set_cookie('iiii',random_str) else: self.write('请先登陆') class ManagerHandler(tornado.web.RequestHandler): def get(self): random_str = self.get_cookie('iiii') xin_user_info = xin.get(random_str,None) if not xin_user_info: self.redirect('/index') else: if xin_user_info.get('is_login',None): time = "%s - %s " %(xin_user_info.get('k1',""),xin_user_info.get('k2',"")) self.write(time) else: self.redirect('/index') settings = { 'template_path':'views', 'static_path':'static' } application = tornado.web.Application([ (r'/index',IndexHandler), (r'/manger',ManagerHandler), ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
5、Session(依赖于cookie)
因为cookie中须要保存客户的不少信息,并且若是信息不少的话,服务端与客户端交互的时候也浪费流量,因此咱们须要用不多的一段字符串来保存不少的信息,这就是咱们所要引进的session。
cookie 和session 的区别:
一、cookie数据存放在客户的浏览器上,session数据放在服务器上。
二、cookie不是很安全,别人能够分析存放在本地的COOKIE并进行COOKIE欺骗 考虑到安全应当使用session。
三、session会在必定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能 考虑到减轻服务器性能方面,应当使用COOKIE。
四、单个cookie保存的数据不能超过4K,不少浏览器都限制一个站点最多保存20个cookie。
五、因此我的建议: 将登录信息等重要信息存放为SESSION 其余信息若是须要保留,能够放在COOKIE中
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web container = {} # container = { # # "第一我的的随机字符串":{}, # # "第一我的的随机字符串":{'k1': 111, 'parents': '你'}, # } class Session: def __init__(self, handler): self.handler = handler self.random_str = None def __genarate_random_str(self): import hashlib import time obj = hashlib.md5() obj.update(bytes(str(time.time()), encoding='utf-8')) random_str = obj.hexdigest() return random_str def __setitem__(self, key, value): # 在container中加入随机字符串 # 定义专属于本身的数据 # 在客户端中写入随机字符串 # 判断,请求的用户是否已有随机字符串 if not self.random_str: random_str = self.handler.get_cookie('__kakaka__') if not random_str: random_str = self.__genarate_random_str() container[random_str] = {} else: # 客户端有随机字符串 if random_str in container.keys(): pass else: random_str = self.__genarate_random_str() container[random_str] = {} self.random_str = random_str # self.random_str = asdfasdfasdfasdf container[self.random_str][key] = value self.handler.set_cookie("__kakaka__", self.random_str) def __getitem__(self, key): # 获取客户端的随机字符串 # 从container中获取专属于个人数据 # 专属信息【key】 random_str = self.handler.get_cookie("__kakaka__") if not random_str: return None # 客户端有随机字符串 user_info_dict = container.get(random_str,None) if not user_info_dict: return None value = user_info_dict.get(key, None) return value class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.session = Session(self) class IndexHandler(BaseHandler): def get(self): if self.get_argument('u',None) in ['alex','eric']: self.session['is_login'] = True self.session['name'] =self.get_argument('u',None) print(container) else: self.write('请你先登陆') class MangerHandler(BaseHandler): def get(self): # s = Session(self) # val = s.get_value('is_login') val = self.session['is_login'] if val: # self.write(s.get_value('name')) self.write(self.session['name']) else: self.write('登陆失败') class LoginHandler(BaseHandler): def get(self,*args,**kwargs): self.render('login.html',status="") def post(self, *args, **kwargs): user = self.get_argument('user',None) pwd = self.get_argument('pwd',None) code = self.get_argument('code',None) check_code = self.session['CheckCode'] if code.upper() == check_code.upper(): self.write('验证码正确') else: self.render('login.html',status ='验证码错误') settings = { 'template_path':'views', 'statics_path':'static', } application = tornado.web.Application([ (r'/index',IndexHandler), (r'/manger',MangerHandler), (r'/login',LoginHandler), ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
#!/usr/bin/env python # -*- coding:utf-8 -*- #!/usr/bin/env python import tornado.web from controllers import home settings = { 'template_path': 'views', # 模板路径的配置 'static_path': "static", # 静态文件 "cookie_secrte": 'uiuoajskfjalsdjf', } # 路由映射,路由系统 application = tornado.web.Application([ (r"/index/(?P<page>\d*)", home.IndexHandler), ], **settings) application.add_handlers('buy.wupeiqi.com$',[ (r"/index/(?P<page>\d*)", buy.IndexHandler), ]) if __name__ == "__main__": # socket运行起来 application.listen(8888) tornado.ioloop.IOLoop.instance().start()
#!/usr/bin/env python # -*- coding:utf-8 -*- class Pagenation: def __init__(self,current_page,all_item,base_url): try: page = int(current_page) except: page = 1 if page < 1: page = 1 all_pager, c = divmod(all_item, 5) if c > 0: all_pager += 1 self.current_page = page self.all_pager = all_pager self.base_url = base_url @property def start(self): return (self.current_page - 1) * 5 @property def end(self): return self.current_page * 5 def string_pager(self): list_page = [] if self.all_pager < 11: s = 1 t = self.all_pager + 1 else: # 总页数大于11 if self.current_page < 6: s = 1 t = 12 else: if (self.current_page + 5) < self.all_pager: s = self.current_page - 5 t = self.current_page + 5 + 1 else: s = self.all_pager - 11 t = self.all_pager + 1 # 首页 first = '<a href="/index/1">首页</a>' list_page.append(first) # 上一页 # 当前页 page if self.current_page == 1: prev = '<a href="javascript:void(0);">上一页</a>' else: prev = '<a href="/index/%s">上一页</a>' % (self.current_page - 1,) list_page.append(prev) for p in range(s, t): # 1-11 if p == self.current_page: temp = '<a class="active" href="/index/%s">%s</a>' % (p, p) else: temp = '<a href="/index/%s">%s</a>' % (p, p) list_page.append(temp) if self.current_page == self.all_pager: nex = '<a href="javascript:void(0);">下一页</a>' else: nex = '<a href="/index/%s">下一页</a>' % (self.current_page + 1,) list_page.append(nex) # 尾页 last = '<a href="/index/%s">尾页</a>' % (self.all_pager,) list_page.append(last) # 跳转 jump = """<input type='text' /><a onclick="Jump('%s',this);">GO</a>""" % ('/index/') script = """<script> function Jump(baseUrl,ths){ var val = ths.previousElementSibling.value; if(val.trim().length>0){ location.href = baseUrl + val; } } </script>""" list_page.append(jump) list_page.append(script) str_page = "".join(list_page) return str_page
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.web from commons import pager LIST_INFO = [ {'username': 'alex', "email": "alex3721@163.com"}, ] for i in range(300): temp = {'username': 'alex'+str(i), "email": str(i) + '123@qq.com'} LIST_INFO.append(temp) class IndexHandler(tornado.web.RequestHandler): def get(self, page): obj = pager.Pagenation(page, len(LIST_INFO), '/index/') current_list = LIST_INFO[obj.start:obj.end] str_page = obj.string_pager() self.render('home/index.html', list_info = current_list, current_page = obj.current_page, str_page = str_page) def post(self,page): user = self.get_argument('username') email = self.get_argument('email') temp = {'username': user, 'email': email} LIST_INFO.append(temp) self.redirect("/index/"+page)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .pager a{ display: inline-block; padding: 5px; margin: 3px; background-color: cadetblue; } .pager a.active{ background-color: brown; color: white; } </style> </head> <body> <h1>提交数据</h1> <form method="post" action="/index/{{current_page}}"> <input name="username" type="text" /> <input name="email" type="text" /> <input type="submit" value="提交" /> </form> <h1>显示数据</h1> <table border="1"> <thead> <tr> <th>用户名</th> <th>邮箱</th> </tr> </thead> <tbody> {% for line in list_info %} <tr> <!--<td>{{line['username']}}</td>--> <td>{{ line['username'] }}</td> <td>{{line['email']}}</td> </tr> {% end %} </tbody> </table> <div class="pager"> {% raw str_page %} </div> </body> </html>
tornado 随机验证码
登录注册的时候,须要验证码的功能,原理为在后台自动建立一张随机图片,而后经过img标签输出到前端。这里咱们须要安装一个pillow的模块,相应的生成随机验证代码文件以下,此外还须要一个字体文件
安装图像处理模块:
pip3 install pillow
#!/usr/bin/env python #coding:utf-8 import random from PIL import Image, ImageDraw, ImageFont, ImageFilter _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z _upper_cases = _letter_cases.upper() # 大写字母 _numbers = ''.join(map(str, range(3, 10))) # 数字 init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(120, 30), chars=init_chars, img_type="GIF", mode="RGB", bg_color=(255, 255, 255), fg_color=(0, 0, 255), font_size=18, font_type="Monaco.ttf", length=4, draw_lines=True, n_line=(1, 2), draw_points=True, point_chance = 2): ''' @todo: 生成验证码图片 @param size: 图片的大小,格式(宽,高),默认为(120, 30) @param chars: 容许的字符集合,格式字符串 @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG @param mode: 图片模式,默认为RGB @param bg_color: 背景颜色,默认为白色 @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF @param font_size: 验证码字体大小 @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf @param length: 验证码字符个数 @param draw_lines: 是否划干扰线 @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效 @param draw_points: 是否画干扰点 @param point_chance: 干扰点出现的几率,大小范围[0, 100] @return: [0]: PIL Image实例 @return: [1]: 验证码图片中的字符串 ''' width, height = size # 宽, 高 img = Image.new(mode, size, bg_color) # 建立图形 draw = ImageDraw.Draw(img) # 建立画笔 def get_chars(): '''生成给定长度的字符串,返回列表格式''' return random.sample(chars, length) def create_lines(): '''绘制干扰线''' line_num = random.randint(*n_line) # 干扰线条数 for i in range(line_num): # 起始点 begin = (random.randint(0, size[0]), random.randint(0, size[1])) #结束点 end = (random.randint(0, size[0]), random.randint(0, size[1])) draw.line([begin, end], fill=(0, 0, 0)) def create_points(): '''绘制干扰点''' chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100] for w in range(width): for h in range(height): tmp = random.randint(0, 100) if tmp > 100 - chance: draw.point((w, h), fill=(0, 0, 0)) def create_strs(): '''绘制验证码字符''' c_chars = get_chars() strs = ' %s ' % ' '.join(c_chars) # 每一个字符先后以空格隔开 font = ImageFont.truetype(font_type, font_size) font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / 3, (height - font_height) / 3), strs, font=font, fill=fg_color) return ''.join(c_chars) if draw_lines: create_lines() if draw_points: create_points() strs = create_strs() # 图形扭曲参数 params = [1 - float(random.randint(1, 2)) / 100, 0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ] img = img.transform(size, Image.PERSPECTIVE, params) # 建立扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界增强(阈值更大) return img, strs
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web container = {} # container = { # # "第一我的的随机字符串":{}, # # "第一我的的随机字符串":{'k1': 111, 'parents': '你'}, # } class Session: def __init__(self, handler): self.handler = handler self.random_str = None def __genarate_random_str(self): import hashlib import time obj = hashlib.md5() obj.update(bytes(str(time.time()), encoding='utf-8')) random_str = obj.hexdigest() return random_str def __setitem__(self, key, value): # 在container中加入随机字符串 # 定义专属于本身的数据 # 在客户端中写入随机字符串 # 判断,请求的用户是否已有随机字符串 if not self.random_str: random_str = self.handler.get_cookie('__kakaka__') if not random_str: random_str = self.__genarate_random_str() container[random_str] = {} else: # 客户端有随机字符串 if random_str in container.keys(): pass else: random_str = self.__genarate_random_str() container[random_str] = {} self.random_str = random_str # self.random_str = asdfasdfasdfasdf container[self.random_str][key] = value self.handler.set_cookie("__kakaka__", self.random_str) def __getitem__(self, key): # 获取客户端的随机字符串 # 从container中获取专属于个人数据 # 专属信息【key】 random_str = self.handler.get_cookie("__kakaka__") if not random_str: return None # 客户端有随机字符串 user_info_dict = container.get(random_str,None) if not user_info_dict: return None value = user_info_dict.get(key, None) return value class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.session = Session(self) class IndexHandler(BaseHandler): def get(self): if self.get_argument('u',None) in ['alex','eric']: self.session['is_login'] = True self.session['name'] =self.get_argument('u',None) print(container) else: self.write('请你先登陆') class MangerHandler(BaseHandler): def get(self): # s = Session(self) # val = s.get_value('is_login') val = self.session['is_login'] if val: # self.write(s.get_value('name')) self.write(self.session['name']) else: self.write('登陆失败') class LoginHandler(BaseHandler): def get(self,*args,**kwargs): self.render('login.html',status="") def post(self, *args, **kwargs): user = self.get_argument('user',None) pwd = self.get_argument('pwd',None) code = self.get_argument('code',None) check_code = self.session['CheckCode'] if code.upper() == check_code.upper(): self.write('验证码正确') else: self.render('login.html',status ='验证码错误') class CheckCodeHandler(BaseHandler): def get(self,*args,**kwargs): import io import check_code mstream = io.BytesIO() #建立图片,并写入验证码 img, code = check_code.create_validate_code() #将图片对象写入到mstrem img.save(mstream,'GIF') self.session['CheckCode']=code self.write(mstream.getvalue()) class CsrfHandler(BaseHandler): def get(self,*args,**kwargs): self.render('csrf.html') def post(self, *args, **kwargs): self.write('csrf.post') settings = { 'template_path':'views', 'statics_path':'static', 'xsrf_cookies':True } application = tornado.web.Application([ (r'/index',IndexHandler), (r'/manger',MangerHandler), (r'/login',LoginHandler), (r'/check_code',CheckCodeHandler), (r'/csrf',CsrfHandler) ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/csrf" method="post"> {% raw xsrf_form_html() %} <p><input name = 'user' type="text" placeholder=“用户名/></p> <p><input name="pwd" type="text" placeholder="密码"></p> <p> <input name="code" type="text" placeholder="验证码"> <img src="/check_code" onclick="ChangeCode(); id = imgCode"> </p> <input type="submit" value="提交"/> <span style="color: #ac2925"></span> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function ChangeCode() { var code = document.getElementById('imgCode'); code.sre += "?"; } </script> </body> </html>
Xss跨站脚本攻击
class IndexHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): jump = '''<input type="text"><a onclick = "Jump('%s',this);">GO</a>'''%('/index/') script = ''' <script> function Jump(baseUrl,ths){ var val = ths.previousElementSibling.value; if (val.trim().length > 0){ location.href = baseUrl + val; } } </script> ''' self.render('index.html',jump=jump,script=script) #传入两个前端代码的字符串
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .pager a{ display: inline-block; padding: 5px; margin: 3px; background-color: #00a2ca; } .pager a.active{ background-color: #0f0f0f; color: white; } </style> </head> <body> <div class="pager"> {% raw jump %} {% raw script%} </div> </body> </html>
csrf跨站请求伪造
get请求的时候,会给浏览器发一个id(cookie),浏览器post请求的时候,携带这个id,而后服务端对其作验证,若是没有这个id的话,就禁止浏览器提交内容。下面来看一下在tornado里面怎么设置,首先须要在settings里面配置 'xsrf_cookies': True,若是这样配置的话,浏览器发送post请求的话这样设置以后,Tornado 将拒绝请求参数中不包含正确的_xsrf
值的 post/put/delete 请求,若是没有携带相应的id(session)则会禁止访问。{% raw xsrf_form_html() %}
是新增的,目的就在于实现上面所说的受权给前端以合法请求。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/csrf" method="post"> {% raw xsrf_form_html() %} <input type="button" value="Ajax CSRF" onclick="SubmitCsrf();" /> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function getCookie(name) { var r = document.cookie.match('\\b'+ name + "=([^:]*)\\b"); return r ? r[1]:undefined; } function SubmitCsrf() { var nid = getCookie("_xsrf"); $.post({ url:'/csrf', data:{'k1':'v1','_xsrf':nid}, success:function (callback) { // Ajax请求发送成功有,自动执行 // callback,服务器write的数据 callback=“csrf.post” console.log(callback); } }); } </script> </body> </html>
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web class CsrfHandler(BaseHandler): def get(self,*args,**kwargs): self.render('csrf.html') def post(self, *args, **kwargs): self.write('csrf.post') settings = { 'template_path':'views', 'statics_path':'static', 'xsrf_cookies':True } application = tornado.web.Application([ (r'/csrf',CsrfHandler) ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start(
ajax
为何使用ajax,局部刷新,减小请求中发送的数据
AJAX,Asynchronous JavaScript and XML (异步的JavaScript和XML),一种建立交互式网页应用的网页开发技术方案。
利用AJAX能够作:
一、注册时,输入用户名自动检测用户是否已经存在。
二、登录时,提示用户名密码错误
三、删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。
首先来看一下一种用iframe标签模拟ajax请求
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web IMG_LIST = [] class PicturesHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.render('iframe.html',img_list = IMG_LIST) def post(self, *args, **kwargs): print(self.get_argument('user')) print(self.get_arguments('favor')) file_maetas = self.request.files['hahaha'] for meta in file_maetas: file_name = meta['filename'] import os with open(os.path.join('static','img',file_name),'wb')as up: up.write(meta["body"]) IMG_LIST.append(file_name) self.write('{"status":1,"message":"mmm"}') settings = { 'template_path':"views", 'static_path':'static', } application = tornado.web.Application([ (r'/iframe',PicturesHandler) ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!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>
Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操做,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)
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...
跨浏览器支持
XmlHttpRequest IE7+, Firefox, Chrome, Opera, etc.
<!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>
jQuery其实就是一个JavaScript的类库,其将复杂的功能作了上层封装,使得开发者能够在其基础上写更少的代码实现更多的功能。
注:2.+版本再也不支持IE9如下的浏览器
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; } }, });
<!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="/c/static/jquery-1.9.1.min.js"></script> <script> function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'GET', data:{"k1":"v1"}, //向服务端发送内容,服务端能够经过self.get_argument("k1")获取 dataType: 'text', success: function(data, statusText, xmlHttpRequest){ console.log(data,statusText); } }) } </script> </body> </html>
4、跨域AJAX
1.什么引发了ajax跨域不能的问题
ajax自己其实是经过XMLHttpRequest对象来进行数据的交互,而浏览器出于安全考虑,不容许js代码进行跨域操做,因此会警告。
特别的:因为同源策略是浏览器的限制,因此请求的发送和响应是能够进行,只不过浏览器不接受罢了。
浏览器同源策略并非对全部的请求均制约:
跨域,跨域名访问,如:http://www.c1.com 域名向 http://www.c2.com域名发送请求。
一、JSONP实现跨域请求(利用script块的特性)
JSONP(JSONP - JSON with Padding是JSON的一种“使用模式”),利用script标签的src属性(浏览器容许script标签跨域)
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): self.write('t1.post') settings = { 'template_path':'views', 'static_path':'static', } application = tornado.web.Application([ (r'/index',IndexHandler), ],**settings) if __name__ == "__main__": application.listen(8001) tornado.ioloop.IOLoop.instance().start()
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self): callback = self.get_argument('callback') self.write('%s([11,22,33]);'% callback) # self.write('func([11,22,33])') def post(self, *args, **kwargs): self.write('t2.post') settings = { 'template_path':'views', 'static_path':'static', } application = tornado.web.Application([ (r'/index',IndexHandler), ],**settings) if __name__ == "__main__": application.listen(8002) tornado.ioloop.IOLoop.instance().start()
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <input type="button" value="Ajax" onclick="DoAjax();"> 9 <input type="button" value="JsonpAjax" onclick="JsonpAjax();"> 10 <script src="/statics/jquery-1.12.4.js"></script> 11 <script> 12 13 function func(arg) { 14 console.log(arg) 15 } 16 function DoAjax() { 17 $.ajax({ 18 url: 'http://w2.com:8002/index', 19 type: 'POST', 20 data: {'k1': 'v1'}, 21 success:function (arg) { 22 console.log(arg) 23 } 24 }); 25 } 26 27 function JsonpAjax() { 28 29 // var tag = document.createElement("script"); 30 // tag.src = 'http://127.0.0.1:8002/index?callback=func'; 31 // document.head.appendChild(tag); 32 // document.head.removeChild(tag); 33 34 $.ajax({ 35 url:'http://127.0.0.1:8002/index', 36 dataType: 'jsonp', 37 jsonp: 'callback', 38 jsonpCallBack: 'func' 39 }) 40 } 41 </script> 42 </body> 43 </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="Ajax" onclick="DoAjax();"/> <input type="button" value="JsonpAjaxJX" onclick="JsonpAjaxJX();"/> <script src="/static/jquery-1.12.4.js"></script> <script src="127.0.0.1:8002/index/static/jquery.cookie.js"></script> <script> function func(arg) { console.log(arg) } function DoAjax() { $.ajax({ url:'http://127.0.0.1:8002/index', type:'post', data:{'k1':'v1'}, success:function (arg) { console.log(arg); } }) } function list(dict) { console.log(dict) } function JsonpAjaxJX() { $.ajax({ url:'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list', dataType:'jsonp', jsonpCallBack:'list' }) } </script> </body> </html>
CORS(客户端不变,服务端设置响应头)
随着技术的发展,如今的浏览器能够支持主动设置从而容许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器容许跨域请求。
* 简单请求 OR 非简单请求
条件: 一、请求方式:HEAD、GET、POST 二、请求头信息: 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 = '域名' 或 '*' *表示全部的域名均可以访问
<!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>
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"}')
b、支持跨域,复杂请求
因为复杂请求时,首先会发送“预检”请求,若是“预检”成功,则发送真实数据。
<!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)
#!/usr/bin/env/python # -*- coding:utf-8 -*- import tornado.web IMG_LIST = [] # class IndexHandler(tornado.web.RequestHandler): # def get(self): # print('asdas') # self.render('index.html') # def post(self, *args, **kwargs): # self.write('{"status":1,"message":"mmm"}') class PicturesHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.render('pictures.html',img_list = IMG_LIST) # self.render('ajaxsc.html',img_list = IMG_LIST) # self.render('ifname.html',img_list = IMG_LIST) # self.render('iframe.html',img_list = IMG_LIST) # def post(self, *args, **kwargs): print(self.get_argument('user')) print(self.get_arguments('favor')) file_maetas = self.request.files['hahaha'] for meta in file_maetas: file_name = meta['filename'] import os with open(os.path.join('static','img',file_name),'wb')as up: up.write(meta["body"]) IMG_LIST.append(file_name) self.write('{"status":1,"message":"mmm"}') settings = { 'template_path':"views", 'static_path':'static', } application = tornado.web.Application([ (r'/pictures',PicturesHandler) # (r'/ajaxsc', PicturesHandler) # (r'/ajaxjq', PicturesHandler) # (r'/ifname',PicturesHandler) # (r'/iframe',PicturesHandler) ],**settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for item in img_list %} <li><img style="width: 200px;height: 200px" src="/static/img/{{item}}"></li> {% end %} </ul> <form action="/pictures" method="post" enctype="multipart/form-data"> <input type="text" name = "user"/> <h1>性格类型</h1> <input type="checkbox" name="favor" value="1"/>暴虐的; <input type="checkbox" name="favor" value="2"/>温和的; <input type="checkbox" name="favor" value="3"/>傻二的; <input type="file" name="hahaha"/> <input type="submit" value="提交"/> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function UploadFile(){ var fileobj = document.getElementById('img').files[0]; var form = new FormData(); form.append('user','uuu'); form.append('favor','1'); form.append('hahaha','fileobj'); var xhr = new XMLHttpRequest(); xhr.open('post','/pictures',true); xhr.send(form); } </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" value="提交按钮"/> <script src="/static/jquery-1.12.4.js"></script> <script> function UploadFile(){ var fileobj = document.getElementById('img').files[0]; var form = new FormData(); form.append('user','uuu'); form.append('favor','1'); form.append('hahaha',fileobj); var xhr = new XMLHttpRequest(); xhr.open('post','/ajaxsc',true); xhr.send(form); } </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" value="提交" /> <script src="/static/jquery-1.12.4.js"></script> <script> function UploadFile(){ var fileObj = $("#img")[0].files[0]; var form = new FormData(); form.append("user", "v1"); form.append('favor','1'); form.append("hahaha", fileObj); $.ajax({ type:'POST', url: '/ajaxjq', data: form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success: function(arg){ console.log(arg); } }) } </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .hide{ display: none; } </style> </head> <body> <form id="my_form" name="form" action="/ifname" method="POST" enctype="multipart/form-data" > <div id="main"> <input name="user" type="text" /> <input name="davor" type="text" /> <input name="hahaha" id="my_file" type="file" /> <input type="button" name="action" value="提交" onclick="redirect()"/> <iframe id='my_iframe' name='my_iframe' src="" class="hide"></iframe> </div> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function redirect(){ document.getElementById('my_iframe').onload = Testt; //找到id为my_iframe 设置 onload 加载完成执行Testt函数 document.getElementById('my_form').target = 'my_iframe'; //将my_form 目标提交到 id为my_iframe document.getElementById('my_form').submit(); } function Testt(ths){ var t = $("#my_iframe").contents().find("body").text(); console.log(t); } </script> </body> </html>
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" /> <script> function UploadFile(){ var fileObj = document.getElementById("img").files[0]; var form = new FormData(); form.append("k1", "v1"); form.append("fff", fileObj); var xhr = new XMLHttpRequest(); xhr.open("post", '/index', true); xhr.send(form); } </script> </body> </html>
<script type="text/javascript"> $(document).ready(function () { $("#formsubmit").click(function () { var iframe = $('<iframe name="postiframe" id="postiframe" style="display: none"></iframe>'); $("body").append(iframe); var form = $('#theuploadform'); form.attr("action", "/upload.aspx"); form.attr("method", "post"); form.attr("encoding", "multipart/form-data"); form.attr("enctype", "multipart/form-data"); form.attr("target", "postiframe"); form.attr("file", $('#userfile').val()); form.submit(); $("#postiframe").load(function () { iframeContents = this.contentWindow.document.body.innerHTML; $("#textarea").html(iframeContents); }); return false; }); }); </script> <form id="theuploadform"> <input id="userfile" name="userfile" size="50" type="file" /> <input id="formsubmit" type="submit" value="Send File" /> </form> <div id="textarea"> </div>