初識 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>