django/tonado/flask/bottle
Django,Flask,Tornado(facebook),Bottle,Butterfly 简单比较
一:常用请求参数的接收
Django
Tornado
Flask
Butterfly
get 请求
post 请求
Bottle
高级用法
二:常用请求方式的区分
Django
Tornado
Flask
Butterfly
三:静态文件和网页模板的处理
Django
Tornado
Flask
bottle
Butterfly
四:模板语法操作
Django
Tornado
Flask
Butterfly
五:Handler 处理函数的返回值
Django
Butterfly
六:WSGI 处理
Django
Bottle
七 启动入口
Bottle
八 访问日志
bottle
一:常用请求参数的接收
Django
request.GET/POST
Tornado
self.get_query_argument()/get_query_arguments()
self.get_body_argument()/get_body_arguments()
self.get_argument()/get_arguments()
Flask
request.args.get('key')
request.form.get(;key')
Butterfly
放在函数的参数列表中 如下面示例中 str_info, 即为请求参数:
get 请求
get 请求的参数和 handler 函数的参数保持一致 (req 后面的参数)
如请求 http://ip:port/hello?str_info=happy
会将 happy
传到 hello 函数中
def hello(req, str_info):
isinstance(req, Request)
return retstat.OK, {"str_info": str_info}, [(__info__, __version__)]
post 请求
httpgateway.read_wsgi_post(req.wsgienv)
Bottle
def route(self, path=None, method='GET', callback=None, name=None, apply=None, skip=None, **config)
if callable(path):
path, callback = None, path
plugins = makelist(apply)
skiplist = makelist(skip)
def decorator(callback):
for rule in makelist(path) or yieldroutes(callback):
for verb in makelist(method):
verb = verb.upper()
cfg = dict(rule=rule, method=verb, callback=callback,
name=name, app=self, config=config,
apply=plugins, skip=skiplist)
self.routes.append(cfg)
cfg['id'] = self.routes.index(cfg)
self.router.add(rule, verb, cfg['id'], name=name)
if DEBUG:
self.ccache[cfg['id']] = self._build_callback(cfg)
return callback
return decorator(callback) if callback else decorator
静态路由, 默认是 GET 请求
#/usr/bin/env python
# coding=utf-8
from bottle import route, run
# 定义路由,即浏览器访问的url
@route('/start)
def start():
return " <h1>hello, this is my first bottleprocess</h1>"
# 开启服务,端口是 8000,授受任何 IP 地址访问
run(host='0.0.0.0', port=8000)
动态路由 -- 动态路由就是可以用 url 传递不同的内容或参数到网页上
#!/usr/bin/env python
# coding=utf-8
from bottle import route,run
@route('/start/<sth>')
def start(sth):
return "<h1>hello, this is my %s bottleprocess</h1>" % sth
run(host='0.0.0.0',port=8000)
高级用法
二:常用请求方式的区分
Django
通过 request.method == "GET" / "POST"进行视图函数中不同请求方式的处理区分
同样可以通过装饰器注解方式:@require_POST @require_GET 方式指定视图函数只能接收那种请求方式
Tornado
可以通过直接重写父类 RequestHandler 中的 get/post/.. 的请求处理方法来实现不同的请求方式的区分
Flask
通过路由装饰器注解的 methods 属性来指定视图处理函数可以接收那种请求方式
@app.route("/", methods=["get", "post"..])
Butterfly
可以通过 req.method == "GET" / "POST" 来区分是 Get 请求还是 POST 请求
备注
Butterfly 在注册路由的时候,如果 is_parse_post 为 True , 则会解析 post 包是否为 json ,并将对应的数据传给后端 handler 中
三:静态文件和网页模板的处理
Django
子模块应用:templates/ 默认保存网页模板;static/ 默认保存静态资源;不需要配置
根项目:settings.py 中通过 TEMPLATES>DIRS 配置网页模板文件夹,通过 STATICFILES_DIRS 配置静态资源文件夹
Django response
+------------------------------+
|HttpResponseBase(six.Iterator)|
+------------------------------+
|
|--------------------+------------------------|
+-----------------+---------------------+ +-----------------+------------+
|StreamingHttpResponse(HttpResponseBase)| |HttpResponse(HttpResponseBase)|
+---------------------------------------+ +------------------------------+
| |||||||| |
V |||||||| V
+---------------------------------------+ |||||||| +---------------------------------------------------------+
|FileResponse(StreamingHttpResponse) | |||||||| |HttpResponseRedirectBase(HttpResponse) |
+---------------------------------------+ |||||||| +---------------------------------------------------------+
|||||||| ||
|||||||| |V
|||||||| |+------------------------------------------------------+
|||||||| ||HttpResponseRedirect(HttpResponseRedirectBase)-----302|
|||||||| |+------------------------------------------------------+
V||||||| V
+---------------------------------------------+||||||| +-------------------------------------------------------+
|HttpResponseNotModified(HttpResponse) 304|||||||| |HttpResponsePermanentRedirect(HttpResponseRedirectBase)|
+---------------------------------------------+||||||| +-------------------------------------------------------+
V||||||
+----------------------------------------------+||||||
|HttpResponseBadRequest(HttpResponse) 400 |||||||
+----------------------------------------------+||||||
V|||||
+-----------------------------------------------+|||||
|HttpResponseNotFound(HttpResponse) 404 ||||||
+-----------------------------------------------+|||||
V||||
+------------------------------------------------+||||
|HttpResponseForbidden(HttpResponse) 403 |||||
+------------------------------------------------+||||
V|||
+-------------------------------------------------+|||
|HttpResponseNotAllowed(HttpResponse) 405 ||||
+-------------------------------------------------+|||
V||
+--------------------------------------------------+||
|HttpResponseGone(HttpResponse) 410 |||
+--------------------------------------------------+||
V|
+---------------------------------------------------+|
|HttpResponseServerError(HttpResponse) 500 ||
+---------------------------------------------------+|
V
+----------------------------------------------------+
|JsonResponse(HttpResponse) |
+----------------------------------------------------+
Tornado
通过 tornado.web.Application 中的配置选项
template_path 配置网页模板文件夹位置,static_path 配置静态资源文件夹位置
Flask
默认 templates/ 中保存网页模板;static/ 中保存静态资源,不需要配置
模板渲染
渲染前的信号 before_render_template.send(app, template=template, context=context)
rv = template.render(context) # 模板渲染
渲染后的信号 template_rendered.send(app, template=template, context=context)
bottle
from bottle import route
from bottle import run
from bottle import static_file
@route('/download/<filename:path>')
def download(filename):
return static_file(filename,root='/Users/wangbin34/test/',download=filename)
run(host='0.0.0.0',port=8080,debug=True)
Butterfly
默认 templates/ 中保存网页模板;static/ 中保存静态资源,不需要配置
四:模板语法操作
解释模型:解析产生一个数据结构表示模板的结构。渲染阶段遍历那个数据结构,基于找到的指令装配结果文本。
编译模型:解析产生某种形式的可直接执行的代码(比如将模板解析成一个 python 函数)。渲染阶段执行那个代码,产生结果。
Django
默认使用自己的模板语法:Django Template Language:DTL 语法
模板引擎使用解释模型
Tornado
默认使用 jinja 模板语法:~经过一定改造的模板语法
模板引擎使用编译模型
Flask
默认使用第三方的 jinja2 模板语法,是在 DTL 语法的基础上完善的一种专门给 python 使用的模板语法
模板引擎使用编译模型
Butterfly
模板引擎使用编译模型
当然,Butterfly 推荐直接使用 Angularjs 框架
五:Handler 处理函数的返回值
Handler 的返回值就是程序的状态码 / 响应包 body/ 响应包 Header 三个部分
Django
from django.http import JsonResponse, HttpResponse
-----django.http package
from django.http.response import (
BadHeaderError, FileResponse, Http404, HttpResponse,
HttpResponseBadRequest, HttpResponseForbidden, HttpResponseGone,
HttpResponseNotAllowed, HttpResponseNotFound, HttpResponseNotModified,
HttpResponsePermanentRedirect, HttpResponseRedirect,
HttpResponseServerError, JsonResponse, StreamingHttpResponse,
)
Butterfly
return retstat.OK, {"randstr": randstr}, [(__info__, __version__)]
> httpstatus: 必须有
> content: 非必须(当返回值为 2 个的时候,第 2 个返回值为 Content)
> headers: 非必须(当返回值为 3 个的时候,第 3 个返回值为 headers)
六:WSGI 处理
Django
位置
django/core/handlers/wsgi.py
代码
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super(WSGIHandler, self).__init__(*args, **kwargs)
self.load_middleware()
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)
request = self.request_class(environ)
response = self.get_response(request)
response._handler_class = self.__class__
status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
start_response(force_str(status), response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
response = environ['wsgi.file_wrapper'](response.file_to_stream)
return response
Bottle
def wsgi(self, environ, start_response):
""" The bottle WSGI-interface. """
try:
out = self._cast(self._handle(environ))
# rfc2616 section 4.3
if response._status_code in (100, 101, 204, 304) or environ['REQUEST_METHOD'] == 'HEAD':
if hasattr(out, 'close'): out.close()
out = []
start_response(response._status_line, response.headerlist)
return out
except (KeyboardInterrupt, SystemExit, MemoryError):
raise
except Exception as E:
if not self.catchall: raise
err = '<h1>Critical error while processing request: %s</h1> ' % html_escape(environ.get('PATH_INFO', '/'))
if DEBUG:
err += '<h2>Error:</h2>\n<pre>\n%s\n</pre>\n' \
'<h2>Traceback:</h2>\n<pre>\n%s\n</pre>\n' \
% (html_escape(repr(E)), html_escape(format_exc()))
environ['wsgi.errors'].write(err)
environ['wsgi.errors'].flush()
headers = [('Content-Type', 'text/html; charset=UTF-8')]
start_response('500 INTERNAL SERVER ERROR', headers, sys.exc_info())
return [tob(err)]
处理 handle
def _handle(self, environ):
...
try:
self.trigger_hook('before_request') --------------------before_request
route, args = self.router.match(environ)
...
out = route.call(**args)
break
except HTTPResponse as E:
out = E
break
except RouteReset:
depr(0, 13, "RouteReset exception deprecated",
"Call route.call() after route.reset() and "
"return the result.")
route.reset()
continue
finally:
self.trigger_hook('after_request')------------------after_request
七 启动入口
Bottle
def run(app=None,
server='wsgiref',
host='127.0.0.1',
port=8080,
interval=1,
reloader=False,
quiet=False,
plugins=None,
debug=None,
config=None,
**kargs):
""" Start a server instance. This method blocks until the server terminates.
:param app: WSGI application or target string supported by :func:`load_app`. (default: :func:`default_app`)
:param server: Server adapter to use. See :data:`server_names` keys for valid names or pass a :class:`ServerAdapter` subclass. (default: `wsgiref`)
:param host: Server address to bind to. Pass ``0.0.0.0`` to listens on all interfaces including the external one. (default: 127.0.0.1)
:param port: Server port to bind to. Values below 1024 require root privileges. (default: 8080)
:param reloader: Start auto-reloading server? (default: False)
:param interval: Auto-reloader interval in seconds (default: 1)
:param quiet: Suppress output to stdout and stderr? (default: False)
:param options: Options passed to the server adapter.
"""
Bottle 的 Server Adapters 简直可以说是 WSGI Server 的博览会,从这里您可以了解目前比较流行的 WSGI 实现
flup
wsgiref
cherrypy
paste
fapws3
tornado
Google Appengine
twisted
diesel
meinheld
gunicorn
eventlet
gevent
rocket
例子
from bottle import route, run
@route('/hello')
def hello():
return "Hello World!"
run(host='localhost', port=8080, debug=True)
八 访问日志
bottle
import datetime
@bottle.hook('after_request')
def log_after_request():
msg = '{ip} - - [{time}] "{method} {uri} {protocol}" {status}'.format(
ip=bottle.request.environ.get('REMOTE_ADDR'),
time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
method=bottle.request.environ.get('REQUEST_METHOD'),
uri=bottle.request.environ.get('PATH_INFO'),
protocol=bottle.request.environ.get('SERVER_PROTOCOL'),
status=bottle.response.status_code,
)
logger.info(msg)
Last updated