快速启动¶
文档的这一部分展示了如何使用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'
正如您所看到的,属性在两个方向上起作用。因此您可以将两者都设置为 status
和 status_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
与请求对象一起使用。
相应地修改响应(状态代码已更改、响应正文已删除、实体头已删除等)