tornado批量获取RequestPayload与FormData数据小结
tornado框架相比Django这样的“重武器”轻便了很多,这也意味着tornado没有像Django那样有很多封装好的方法供我们使用,在处理前端请求的数据也是如此。
本文总结一下tornado框架处理前端传来的RequestPayload与FormData两种格式的数据的方法,因为现在很少有人传Query String Parameters这种类型的数据了,所以就不介绍了。
http请求参数之Query String Parameters、Form Data、Request Payload
Query String Parameters
当发起一次GET请求时,参数会以url string的形式进行传递。即?
后的字符串则为其请求参数,并以&
作为分隔符。
如下http请求报文头:
// General Request URL: http://foo.com?x=1&y=2 Request Method: GET
// Query String Parameters x=1&y=2
Form Data
当发起一次POST请求时,若未指定content-type,则默认content-type为application/x-www-form-urlencoded。即参数会以Form Data的形式进行传递,不会显式出现在请求url中。
如下http请求报头:
// General Request URL: http://foo.com Request Method: POST
// Request Headers content-type: application/x-www-form-urlencoded; charset=UTF-8 // Form Data x=1&y=2
Request Payload
当发起一次POST请求时,若content-type为application/json,则参数会以Request Payload的形式进行传递(显然的,数据格式为JSON),不会显式出现在请求url中。
如下http请求报头:
/ General Request URL: http://foo.com Request Method: POST
/ Request Headers content-type: application/json; charset=UTF-8 // Request Payload x=1&y=2
tornado处理Request Payload数据
ajax请求可以设置content-type请求头!
前端的请求如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index</title> </head> <body> title:<input id="t1"> <br><br> author:<input id="a1"> <br><br> <button id="button">提交</button> <script src="{{ static_url('jquery-1.12.4.js') }}"></script> <script> $('#button').click(function () { title = $("#t1").val(); author = $("#a1").val(); // console.log(title, author); $.ajax({ url: '/index', type: 'POST', contentType: 'application/json', //设置请求头,注明编码格式 data: JSON.stringify({"title": title, "author": author}), // 注意得先序列化才能传递 success: function (data) { console.log(data); } }) }); </script> </body> </html>
后端tornado代码如下:
# -*- coding:utf-8 -*- import json import os.path import tornado.locale import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define, options from logics import handle_payload_args define("port", default=8006, help="run on the given port", type=int) class Application(tornado.web.Application): def __init__(self): handlers = [ # 主页 (r"/index", MainHandler), ] settings = dict( template_path=os.path.join(os.path.dirname(__file__),"templates"), static_path=os.path.join(os.path.dirname(__file__),"static"), debug=True, ) # 执行父类__init__方法 tornado.web.Application.__init__(self, handlers,**settings) from tornado.escape import json_decode class MainHandler(tornado.web.RequestHandler): def get(self): self.render( "index.html", ) def post(self): ret = self.request.body # 二进制 print("request.body:",ret,type(ret)) # request.body: b'{"title":"222","author":"123"}' <class 'bytes'> req = json_decode(ret) # 直接用json_decode就可以 print("req:",req,type(req)) # req: {'title': '222', 'author': '123'} <class 'dict'> result = json.dumps(req,ensure_ascii=False) # 设置ensure_ascii=False,防止中文乱码 self.write(result) if __name__ == "__main__": tornado.options.parse_command_line() http_server = tornado.httpserver.HTTPServer(Application()) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
页面调试效果
tornado处理Form Data数据 ***
前端可以用form表单模拟传递数据:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index</title> </head> <body> <form action="" method="post"> title:<input type="text" value="" name="title"> <br><br> author:<input type="text" value="" name="author" > <br><br> <input type="submit"> </form> </body> </html>
tornado没有Django封装的POST属性,需要通过get_argument方法一个个获取,太麻烦,可以写一个方法封装一下:
# -*- coding:utf-8 -*- import json import os.path import tornado.locale import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define, options define("port", default=8006, help="run on the given port", type=int) class Application(tornado.web.Application): def __init__(self): handlers = [ # 主页 (r"/index", MainHandler), ] settings = dict( template_path=os.path.join(os.path.dirname(__file__),"templates"), static_path=os.path.join(os.path.dirname(__file__),"static"), debug=True, ) # 执行父类__init__方法 tornado.web.Application.__init__(self, handlers,**settings) class MainHandler(tornado.web.RequestHandler): def get(self): self.render( "index.html", ) # 自己定义一个批量处理的方法 def handle_formdata_args(self, query_title): result = dict() for title in query_title: value = self.get_argument(title) # 本质上还是用了get_argument方法获取值 result[title] = value return result def post(self): ret = self.request.body # 二进制 print("request.body:",ret,type(ret)) # request.body: b'title=22211&author=12333' <class 'bytes'> # 提前吧需要查询的参数写进去 —— 注意这里不能直接用json_decode!会报错! query_title = ["title", "author"] req = self.handle_formdata_args(query_title) print("req:",req,type(req)) # req: {'title': '222', 'author': '123'} <class 'dict'> result = json.dumps(req,ensure_ascii=False) # 设置ensure_ascii=False 避免中文乱码 self.write(result) if __name__ == "__main__": tornado.options.parse_command_line() http_server = tornado.httpserver.HTTPServer(Application()) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
更方便的方法
# -*- coding:utf-8 -*- import json import os.path import tornado.locale import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define, options define("port", default=8006, help="run on the given port", type=int) class Application(tornado.web.Application): def __init__(self): handlers = [ # 主页 (r"/index", MainHandler), ] settings = dict( template_path=os.path.join(os.path.dirname(__file__),"templates"), static_path=os.path.join(os.path.dirname(__file__),"static"), debug=True, ) # 执行父类__init__方法 tornado.web.Application.__init__(self, handlers,**settings) class MainHandler(tornado.web.RequestHandler): def get(self): self.render( "index.html", ) def handle_formdata_args2(self): result = dict() body = self.request.body # 二进制 print("request.body:", body, type(body)) # request.body: b'title=123123&author=123' <class 'bytes'> body_str = body.decode("utf-8") print("body_str:",body_str,type(body_str)) # body_str: title=123123&author=123 <class 'str'> # 根据规律切割body_str,找出来所有的"key" —— 特别注意:"key"不能有中文!!!否则这个方法不能用!用上面介绍的方法!!! query_lst = body_str.split("&",1) # 切割一次防止用户输入的也有&号! print(query_lst) # ['title=123123', 'author=123'] title_lst = [] for query_str in query_lst: title = query_str.split("=",1)[0] # 切割一次!防止用户输入的也有等号! title_lst.append(title) print(title_lst) # ['title', 'author'] for title in title_lst: value = self.get_argument(title) result[title] = value return result def post(self): req = self.handle_formdata_args2() result = json.dumps(req,ensure_ascii=False) self.write(result) if __name__ == "__main__": tornado.options.parse_command_line() http_server = tornado.httpserver.HTTPServer(Application()) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
前端调试效果
在基类的prepare方法中提前处理的思路
我们可以在基类的prepare方法中提前判断一下前端的请求头中contenttype的类型,然后将请求的数据封装成类的属性:
接下来继承这个基类的子类就可以使用body_args这个属性 —— 从前端获取的json格式的数据,来进行接下来的逻辑处理了。