flask中的werkzeug
Werkzeug是一个Python库,用于开发Web应用程序。它是一个WSGI(Web Server Gateway Interface)工具包,提供了一系列实用功能来帮助开发者处理HTTP请求、响应、URLs等等。Werkzeug的设计非常灵活,可以用作构建各种Web框架的基础。
Werkzeug的特性包括:
- 请求和响应对象:Werkzeug为HTTP请求和响应提供了易于使用的包装器,使得开发者可以更方便地处理这些请求和响应。
- URL路由:Werkzeug提供了强大的URL路由功能,能够帮助开发者将URL映射到相应的处理函数。(文末进行举例说明)
- 错误处理:Werkzeug提供了异常处理机制,可以方便地处理HTTP错误,并且提供了一个交互式的调试器,使得在开发过程中调试错误更加方便。
- HTTP工具:Werkzeug还提供了一些其他的HTTP相关的工具,比如处理cookies、文件上传等。
例子
from werkzeug.wrappers import Request, Response
def application(environ, start_response):
request = Request(environ)
text = 'Hello, %s!' % request.args.get('name', 'World')
response = Response(text, mimetype='text/plain')
return response(environ, start_response)
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, application)
def application(environ, start_response):
这定义了一个函数,名为application
。这个函数符合WSGI的规范,是一个典型的WSGI应用。它接受两个参数,environ
是一个包含所有HTTP请求信息的字典,start_response
是一个发送HTTP响应的回调函数。
request = Request(environ)
这行代码用Werkzeug的Request
类将environ
字典包装为一个Request
对象,这样我们就可以方便地通过面向对象的方式访问HTTP请求的信息。
text = 'Hello, %s!' % request.args.get('name', 'World')
这行代码从request.args
(一个MultiDict,包含所有的查询参数)中获取’name’参数的值,如果没有找到’name’参数,那么就默认为’World’。然后使用这个值生成一段问候语。
response = Response(text, mimetype='text/plain')
这行代码创建一个Response
对象,它接受两个参数,第一个参数是HTTP响应的主体(在这个例子中是一段问候语),第二个参数是响应的MIME类型,这里设置为’text/plain’,表示响应的内容是纯文本。
return response(environ, start_response)
最后,这行代码调用response
对象的__call__
方法,传入environ
和start_response
。这样Response
对象就会按照WSGI的规范,调用start_response
发送HTTP响应。因为Response
类是可调用的,所以我们可以将其作为WSGI应用返回。
要发送带有 ‘name’ 参数的请求,你只需要在URL中添加一个查询参数即可。例如,如果你的服务器运行在localhost的4000端口上,你可以通过以下URL发送请求:
http://localhost:4000/?name=YourName
在这个URL中,‘?’ 后面的部分是查询参数。你可以通过更改 ‘YourName’ 来改变 ‘name’ 参数的值。例如,如果你将 ‘YourName’ 改为 ‘Alice’,那么服务器将会响应 ‘Hello, Alice!’。
werkzeug的路由系统
在 Werkzeug 中,路由的处理主要通过 werkzeug.routing
模块中的 Map
和 Rule
类来实现。下面是一个简单的示例:
from werkzeug.routing import Map, Rule
from werkzeug.wrappers import Request, Response
# 创建一个 URL 映射
url_map = Map([
Rule('/', endpoint='hello'), # 将根路径 / 映射到 'hello' 端点
Rule('/bye', endpoint='bye') # 将 /bye 路径映射到 'bye' 端点
])
# 创建处理函数字典
view_functions = {
'hello': lambda: Response('Hello, World!'),
'bye': lambda: Response('Goodbye, World!')
}
# 创建 WSGI 应用
def application(environ, start_response):
request = Request(environ)
urls = url_map.bind_to_environ(request.environ) # 将环境绑定到 URL 映射
endpoint, args = urls.match() # 从 URL 映射中匹配请求路径
response = view_functions[endpoint]() # 使用相应的处理函数处理请求
return response(environ, start_response)
# 在主程序中运行 WSGI 服务器
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, application)
在这个例子中,我们首先创建了一个 Map
对象,它包含了两个 Rule
。每个 Rule
都定义了一个 URL 模式和一个对应的端点。然后,我们创建了一个字典 view_functions
,它将每个端点映射到一个处理函数。
然后,我们创建了一个 WSGI 应用 application
。这个应用首先使用 Map.bind_to_environ
方法将请求环境绑定到 URL 映射,然后使用 MapAdapter.match
方法从 URL 映射中匹配请求路径,最后使用相应的处理函数处理请求。
最后,我们在主程序中使用 run_simple
函数运行一个 WSGI 服务器,将 application
作为处理函数。这样,当你访问 http://localhost:4000/
时,你将看到 ‘Hello, World!’,当你访问 http://localhost:4000/bye
时,你将看到 ‘Goodbye, World!’。
重点
urls = url_map.bind_to_environ(request.environ)
这行代码的作用是创建一个 MapAdapter
对象。 MapAdapter
对象是 Werkzeug 路由系统的关键组成部分,它的主要任务是根据当前的请求环境,匹配最合适的 URL 规则。
这里的 request.environ
是一个字典,包含了所有的 WSGI 环境变量,例如 HTTP 方法、路径、查询参数等。当我们调用 url_map.bind_to_environ(request.environ)
时,Werkzeug 实际上是在创建一个能够理解当前请求环境的 MapAdapter
对象。
然后,你就可以在这个 MapAdapter
对象上调用 match()
方法,来匹配当前请求的 URL。如果找到了匹配的规则,match()
方法会返回一个包含端点名称和路径参数的元组。
假设我们访问 “http://localhost:4000/bye” 这个 URL,那么在 application
函数中:
request = Request(environ)
:这行代码将请求环境包装成一个Request
对象,方便我们访问请求相关的信息。urls = url_map.bind_to_environ(request.environ)
:这行代码将当前的请求环境(包括 HTTP 方法、路径 ‘/bye’ 等)绑定到url_map
上,并返回一个MapAdapter
对象urls
。urls
了解如何将请求环境与url_map
中定义的 URL 规则进行匹配。endpoint, args = urls.match()
:这行代码在urls
中查找匹配当前请求环境的 URL 规则。在这个例子中,它找到了规则Rule('/bye', endpoint='bye')
,并返回其对应的端点'bye'
。response = view_functions[endpoint]()
:这行代码查找与端点'bye'
对应的处理函数(即view_functions['bye']
),并调用这个函数处理请求。在这个例子中,处理函数返回了一个Response
对象,其内容为'Goodbye, World!'
。return response(environ, start_response)
:这行代码将响应返回给客户端。
所以,url_map.bind_to_environ(request.environ)
的作用就是创建一个 MapAdapter
对象,这个对象能够根据当前的请求环境,在 url_map
中找到匹配的 URL 规则。
MapAdapter类介绍
MapAdapter
是Werkzeug路由系统中的一个重要类,用于处理URL规则与具体请求之间的匹配与生成URL。以下是MapAdapter
中的一些重要的方法和属性:
match(path_info=None, method=None)
: 尝试匹配给定的路径和方法(如果提供)与Map
中的Rule
规则。如果找到匹配的规则,这个方法会返回一个元组,包含端点名称和路径参数。如果没有找到匹配的规则,这个方法会抛出NotFound
异常。如果找到了多个匹配的规则,这个方法会抛出MethodNotAllowed
异常。build(endpoint, values=None, method=None, force_external=False, append_unknown=True)
: 生成一个URL,该URL与指定的端点和值匹配。这个方法在你需要生成应用内的URL时非常有用,例如在重定向或链接生成时。bind_to_environ(environ, server_name=None)
: 生成一个新的MapAdapter
,该MapAdapter
是当前MapAdapter
的副本,但绑定到给定的WSGI环境。这在处理请求时非常有用,因为它可以创建一个理解当前请求的MapAdapter
。bind(server_name, script_name=None, subdomain=None, url_scheme='http', default_method='GET')
: 生成一个新的MapAdapter
,该MapAdapter
是当前MapAdapter
的副本,但绑定到指定的服务器名称、脚本名称、子域名和URL方案。这在你需要在不同环境中测试路由系统时非常有用。
此外,MapAdapter
还包含一些用于配置路由系统的属性,例如 map
(与 MapAdapter
关联的 Map
对象)、server_name
(服务器的名称)和 url_scheme
(URL的方案,通常是 ‘http’ 或 ‘https’)。
MapAdapter
本身并不存储任何请求或响应信息。它的主要任务是理解如何将请求匹配到 Map
中的 Rule
规则,并根据这些规则生成URL。