快速启动

文档的这一部分展示了如何使用Werkzeug最重要的部分。它旨在作为开发人员对 PEP 3333 (wsgi)和 RFC 2616 (http)。

WSGI环境

wsgi环境包含用户请求传输到应用程序的所有信息。它被传递给wsgi应用程序,但您也可以使用 create_environ() 帮手:

>>> from werkzeug.test import create_environ
>>> environ = create_environ('/foo', 'http://localhost:8080/')

现在我们有了一个可以玩的环境:

>>> environ['PATH_INFO']
'/foo'
>>> environ['SCRIPT_NAME']
''
>>> environ['SERVER_NAME']
'localhost'

通常没有人愿意直接使用environ,因为它使用了一个令人困惑的字符串编码方案,而且除了手工解析表单数据外,它不提供任何访问表单数据的方法。

输入请求

要访问请求数据, Request 物体更有趣。它包裹着 environ 并提供对数据的只读访问:

>>> from werkzeug.wrappers import Request
>>> request = Request(environ)

现在您可以访问重要的变量,Werkzeug将为您解析它们并在有意义的地方解码它们。

>>> request.path
'/foo'
>>> request.script_root
''
>>> request.host
'localhost:8080'
>>> request.url
'http://localhost:8080/foo'

我们还可以找出请求使用的HTTP方法:

>>> request.method
'GET'

这样我们还可以访问URL参数(查询字符串)和在POST/PUT请求中传输的数据。

出于测试目的,我们可以使用 from_values() 方法:

>>> from io import StringIO
>>> data = "name=this+is+encoded+form+data&another_key=another+one"
>>> request = Request.from_values(query_string='foo=bar&blah=blafasel',
...    content_length=len(data), input_stream=StringIO(data),
...    content_type='application/x-www-form-urlencoded',
...    method='POST')
...
>>> request.method
'POST'

现在我们可以轻松访问URL参数:

>>> request.args.keys()
['blah', 'foo']
>>> request.args['blah']
'blafasel'

提供的表单数据相同:

>>> request.form['name']
'this is encoded form data'

从这个例子中可以看出,处理上载的文件并不难:

def store_file(request):
    file = request.files.get('my_file')
    if file:
        file.save('/where/to/store/the/file.txt')
    else:
        handle_the_error()

文件表示为 FileStorage 提供一些常用操作的对象。

请求标头可以通过使用 headers 属性:

>>> request.headers['Content-Length']
'54'
>>> request.headers['Content-Type']
'application/x-www-form-urlencoded'

头部的键当然不区分大小写。

标题分析

还有更多。Werkzeug提供了对常用HTTP头和其他请求数据的方便访问。

让我们用典型Web浏览器传输的所有数据创建一个请求对象,这样我们就可以使用它:

>>> environ = create_environ()
>>> environ.update(
...     HTTP_ACCEPT='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
...     HTTP_ACCEPT_LANGUAGE='de-at,en-us;q=0.8,en;q=0.5',
...     HTTP_ACCEPT_ENCODING='gzip,deflate',
...     HTTP_ACCEPT_CHARSET='ISO-8859-1,utf-8;q=0.7,*;q=0.7',
...     HTTP_IF_MODIFIED_SINCE='Fri, 20 Feb 2009 10:10:25 GMT',
...     HTTP_IF_NONE_MATCH='"e51c9-1e5d-46356dc86c640"',
...     HTTP_CACHE_CONTROL='max-age=0'
... )
...
>>> request = Request(environ)

通过Accept标头,浏览器通知Web应用程序它可以处理哪些MIMETYPE以及处理得有多好。所有Accept标头都按质量排序,最好的项目是第一个:

>>> request.accept_mimetypes.best
'text/html'
>>> 'application/xhtml+xml' in request.accept_mimetypes
True
>>> print request.accept_mimetypes["application/json"]
0.8

同样适用于语言:

>>> request.accept_languages.best
'de-at'
>>> request.accept_languages.values()
['de-at', 'en-us', 'en']

当然还有编码和字符集:

>>> 'gzip' in request.accept_encodings
True
>>> request.accept_charsets.best
'ISO-8859-1'
>>> 'utf-8' in request.accept_charsets
True

规范化是可用的,因此您可以安全地使用其他表单来执行包含检查:

>>> 'UTF8' in request.accept_charsets
True
>>> 'de_AT' in request.accept_languages
True

电子标签和其他条件头也可以用解析的形式提供:

>>> request.if_modified_since
datetime.datetime(2009, 2, 20, 10, 10, 25, tzinfo=datetime.timezone.utc)
>>> request.if_none_match
<ETags '"e51c9-1e5d-46356dc86c640"'>
>>> request.cache_control
<RequestCacheControl 'max-age=0'>
>>> request.cache_control.max_age
0
>>> 'e51c9-1e5d-46356dc86c640' in request.if_none_match
True

响应

响应对象与请求对象相反。它们用于将数据发送回客户机。实际上,响应对象只不过是美化的wsgi应用程序。

所以你所做的不是 返回 来自wsgi应用程序的响应对象,但是 打电话 它作为wsgi应用程序在您的wsgi应用程序中运行,并返回该调用的返回值。

想象一下您的标准wsgi“Hello World”应用程序:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['Hello World!']

对于响应对象,它将如下所示:

from werkzeug.wrappers import Response

def application(environ, start_response):
    response = Response('Hello World!')
    return response(environ, start_response)

此外,与请求对象不同,响应对象设计为要修改。因此,您可以使用它们:

>>> from werkzeug.wrappers import Response
>>> response = Response("Hello World!")
>>> response.headers['content-type']
'text/plain; charset=utf-8'
>>> response.data
'Hello World!'
>>> response.headers['content-length'] = len(response.data)

您可以用同样的方法修改响应的状态。或者只是代码,或者提供一条消息:

>>> response.status
'200 OK'
>>> response.status = '404 Not Found'
>>> response.status_code
404
>>> response.status_code = 400
>>> response.status
'400 BAD REQUEST'

正如您所看到的,属性在两个方向上起作用。因此您可以将两者都设置为 statusstatus_code 而这种变化会反映到另一个人身上。

此外,公共头作为属性或使用设置/检索它们的方法公开:

>>> response.content_length
12
>>> from datetime import datetime, timezone
>>> response.date = datetime(2009, 2, 20, 17, 42, 51, tzinfo=timezone.utc)
>>> response.headers['Date']
'Fri, 20 Feb 2009 17:42:51 GMT'

因为etags可以是弱的或强的,所以有一些方法可以设置它们:

>>> response.set_etag("12345-abcd")
>>> response.headers['etag']
'"12345-abcd"'
>>> response.get_etag()
('12345-abcd', False)
>>> response.set_etag("12345-abcd", weak=True)
>>> response.get_etag()
('12345-abcd', True)

一些头文件作为可变结构提供。例如,大多数 Content- 标题是一组值:

>>> response.content_language.add('en-us')
>>> response.content_language.add('en')
>>> response.headers['Content-Language']
'en-us, en'

在这里,这两个方向都适用:

>>> response.headers['Content-Language'] = 'de-AT, de'
>>> response.content_language
HeaderSet(['de-AT', 'de'])

也可以这样设置身份验证头:

>>> response.www_authenticate.set_basic("My protected resource")
>>> response.headers['www-authenticate']
'Basic realm="My protected resource"'

也可以设置cookies:

>>> response.set_cookie('name', 'value')
>>> response.headers['Set-Cookie']
'name=value; Path=/'
>>> response.set_cookie('name2', 'value2')

如果标题出现多次,则可以使用 getlist() 获取头的所有值的方法:

>>> response.headers.getlist('Set-Cookie')
['name=value; Path=/', 'name2=value2; Path=/']

最后,如果您设置了所有条件值,则可以针对请求设置响应条件。这意味着如果请求可以确保它已经拥有该信息,则除了报头之外,不会通过网络发送任何数据,从而节省了通信量。为此,您应该至少设置一个ETag(用于比较)和Date标头,然后调用 make_conditional 与请求对象一起使用。

相应地修改响应(状态代码已更改、响应正文已删除、实体头已删除等)