werkzeug 是 python WSGI (web server gateway interface, web服务器网关接口) 的应用程序库;werkzeug 没有任何外部依赖项,开发人员可以选择模板引擎、数据库适配器,以及如何处理请求。werkzeug是一个德语名词,译为“工具”的意思;他的作者Armin Ronacher(习惯人们称他为 mitsuhiko) 还着手写了其他的web相关程序库:Jinja2(一个html模板渲染引擎)、Flask(基于werkzeug的高阶web框架)。
WSGI 是一个web服务器的规范接口,描述了一个web服务器应该如何处理HTTP请求,并对请求做出响应,PEP333 对webserver网关的功能进行了描述,werkzeug基于此文档实现了一个webserver;这和Java Servlet 平齐,作为http服务器的基础程序,可以快速入手。HTTP协议作为应用层协议,是依赖传输层的TCP协议,传输层的协议可以用socket套接字描述(IP-port), werkzeug使用python网络模块socket接收请求,然后解析HTTP报文,拿到相应的请求数据。werkzeug特性:
werkzeug 系列文章将会逐一介绍werkzeug的上述特性,用于编写完整的web应用程序,以及通过完整的一个例子编写一个类似于SpringMVC分层的web实例。werkzueug 路由模块可以作为控制层, 视图层(HTML页面)由谁来呈现呢?交由模板渲染引擎Jinja2(可以在html页面使用python语法将应用数据呈现),模型层(实体层) -数据的持久化我们需要借助python数据库操作模块(db-api: pymysql/psycopg2) 来进行。
werkzeug 现在已经发布到了2.0版本(引入了typing, 代码中加入了类型解释,代码不容阅读),我们使用werkzeug的稳定1.0版本,主体程序差别不大。安装:
pip install Werkeug==1.0.0
def application(environ, start_response):
from werkzeug.wrappers import Response
response = Response('Hello World!', mimetype='text/plain')
return response(environ, start_response)
if __name__ == "__main__":
from werkzeug.serving import run_simple
run_simple("localhost", 5000, application)
'''
run_simple 用于跑起一个web应用用于监听请求
run_simple(hostname, port, app)
app 必须带有两个参数(environ, start_response)以供调用
对于类来说,__call__(environ, start_reponse),实例化一个对象后,实现对象可函数化调用
app 返回一个Response对象后,调用response(environ, start_response)
'''
werkzueg路由系统由werkzueg.routing模块所定义,路由首先需要绑定到适配器上,请求路径的匹配由适配器调用规则Rule的匹配方法;同一个路径,对应不同的请求方法(GET、POST)会匹配出不同的端点,路径是由一个复杂的正则匹配出来的(详解见python正则表达式-语义化正则)。
from werkzeug.routing import Map, Rule
from werkzeug.wrappers import Request, Response
from werkzeug.exceptions import NotFound
from werkzeug.routing import Map, Rule
'''
Rule(string='', methods=["POST", "GET"], endpoint)
endpoint 可以是一个可直接调用的函数,也可以是函数名称(通过getattr()获取并调用)
'''
# 路由的映射可以做为一个全局变量定义使用
url_map = Map([
Rule('/', endpoint="show"),
Rule("/about", endpoint="show"),
Rule("/detail/<id>", endpoint="show"),
Rule("/home/<int:id>", endpoint="show"),
])
# 一个最完整的url模式,url的匹配通过正则表达式匹配 /path/<type_converter(cvt_args):func_args>
url_map.add(Rule("/page/<string(length=10):id>", endpoint="show"))
class App:
def show(self, request, id=None):
path = request.path
show_str = "This is Error page!"
if path == "/":
show_str = "This is Index page!"
elif path == "/about":
show_str = "This is About page!"
elif path.find("/detail") != -1:
show_str = f"This is No.{id} Detail page!"
elif path.find("/home") != -1:
show_str = f"This is NO.{id} Home page!"
elif path.find("/user") != -1:
show_str = f"This is NO.{id} User page!"
return Response(show_str, mimetype="text/plain")
def dispatch_request(self, environ, start_response):
request = Request(environ)
adapter = url_map.bind_to_environ(environ)
try:
endpoint, args = adapter.match()
handler = getattr(self, endpoint)
response = handler(request, **args)
except NotFound as e:
response = e
return response(environ, start_response)
def __call__(self, environ, start_response):
return self.dispatch_request(environ, start_response)
if __name__ == "__main__":
from werkzeug.serving import run_simple
application = App()
run_simple("localhost", 5000, application)
对于css、js、image等静态资源的访问,werkzueg提供了SharedMiddleWare来将本地路径和请求路径匹配,我们需要将App类用SharedMiddleWare进行装配:
from werkzeug.middleware.shared_data import SharedDataMiddleware
import os
local_static_path = os.path.join(os.path.dirname(__file__), "static")
app = SharedDataMiddleware(app, {"/static":, local_static_path)})
当一个带有/static/style.css的请求过来时,sharedmiddleware会在local_static_path下寻找style.css文件,并返回二进制文件流(application/octet-stream)到浏览器。这就会递归将所有local_static_path下的文件暴露到/static请求下,发布了所有静态资源。这个同样可以用于用户上传的图片与文件的访问。
Request对象会将envrion的上下文环境进行封装,得到一个请求对象,常用的request对象的参数由下表说明:
from werkzeug.wrappers import Request
request = Request(environ)
# 所有的HTTP实体都被封装成了ImmutableMultiDict, 支持字典['key']取, 也支持对象.取, 前提该key存在
# 所有特殊字典都组织在werkzeug.datastructures 模块里,有兴趣可以看一下里面的方法
HTTP实体 | Request对象参数 | 用法说明 |
---|---|---|
请求路径 | request.path | |
地址栏参数 | request.args | |
请求方法 | request.method | |
客户端地址 | reqest.remote_addr | |
表单参数 | request.form | 转字典:request.form.to_dict() |
提交文件 | request.files | 获取文件二进制流: request.files.get(‘img’)->FileStorage 获取多个文件:getlist(‘img’) 存储文件: img.save(dst_path) |
客户端cookies | request.cookies | 根据cookies装配session(seesionId) |
本篇关于werkzueg基础操作:如何跑起一个webserver、 获取表单数据、处理请求、分派路由,下一篇将是关于python数据库操作。