tornado框架相比Django这样的“重武器”轻便了很多,这也意味着tornado没有像Django那样有很多封装好的方法供我们使用,在处理前端请求的数据也是如此。
本文总结一下tornado框架处理前端传来的RequestPayload与FormData两种格式的数据的方法,因为现在很少有人传Query String Parameters这种类型的数据了,所以就不介绍了。
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
ajax请求可以设置content-type请求头!
前端的请求如下:
title:
author:
$('#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);
}
})
});
后端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''
req= json_decode(ret) # 直接用json_decode就可以
print("req:",req,type(req)) # req: {'title': '222', 'author': '123'}
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()
页面调试效果
前端可以用form表单模拟传递数据:
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'
# 提前吧需要查询的参数写进去 ―― 注意这里不能直接用json_decode!会报错!
query_title=["title", "author"]
req = self.handle_formdata_args(query_title)
print("req:",req,type(req)) # req: {'title': '222', 'author': '123'}
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'
body_str=body.decode("utf-8")
print("body_str:",body_str,type(body_str)) # body_str: title=123123&author=123
# 根据规律切割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方法中提前判断一下前端的请求头中contenttype的类型,然后将请求的数据封装成类的属性:
接下来继承这个基类的子类就可以使用body_args这个属性 ―― 从前端获取的json格式的数据,来进行接下来的逻辑处理了。