# 快速開始
文檔的這部分內容將會向你展示如何使用 Werkzeug 最重要的部分。意在讓開發者對[**PEP 333**](http://www.python.org/dev/peps/pep-0333) (WSGI) 和 [**RFC 2616**](http://tools.ietf.org/html/rfc2616.html) (HTTP) 有一個基本的了解。
> 警告
> 確保在文檔建議的地方導入所有對象。理論上從不同的地方導入對象是可行的,但是在這卻是不被支持的。
例如 MultiDict 是一個 werkzeug 模塊,但它在內部卻不是 Werkzeug實現的。
### WSGI 環境
WSGI 環境包含所有用戶向應用發送信息。你可以通過它向 WSGI 發送信息,但是你也可以使用 create_environ() 輔助函數創建一個 WSGI 環境字典:
~~~
>>> 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
Request 對象訪問請求數據是很有趣的。它封裝 environ 并提供只讀的方法訪問數據:
~~~
>>> from werkzeug.wrappers import Request
>>> request = Request(environ)
~~~
現在你可以訪問重要的變量,Werkzeug 將會幫你解析并解碼他們。默認的字符集是 utf-8但是你可以通過 Request 子類更改。
~~~
>>> request.path
u'/foo'
>>> request.script_root
u''
>>> request.host
'localhost:8080'
>>> request.url
'http://localhost:8080/foo'
~~~
我們也可以得到 HTTP 請求方法:
~~~
>>> request.method
'GET'
~~~
通過這個方法我們可以訪問 URL 參數(查詢的字符串) 和 POST/PUT 請求提交的數據。
為了測試,我們通過 from_values() 方法得到的數據創建一個請求對象:
~~~
>>> from cStringIO 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']
u'blafasel'
~~~
訪問提交的數據也是一樣的:
~~~
>>> request.form['name']
u'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()
~~~
files 代表一個 FileStorage 對象,提供一些常見的操作。
通過 headers 的屬性可以得到請求的 headers。
~~~
>>> request.headers['Content-Length']
'54'
>>> request.headers['Content-Type']
'application/x-www-form-urlencoded'
~~~
頭信息的鍵不區分大小寫。
### 解析 Headers
這里還有更多 Werkzeug 提供的使用 HTTP headers 和其他請求數據的常用的方法。
讓我們用典型的 web 瀏覽器發送數據來創建一個請求對象。以便于更真實的測試:
~~~
>>> environ = create_environ()
>>> environ.update(
... HTTP_USER_AGENT='Mozilla/5.0 (Macintosh; U; Mac OS X 10.5; en-US; ) Firefox/3.1',
... 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)
~~~
讓我們從最沒有用(- -)的 headers 開始: the user agent:
~~~
>>> request.user_agent.browser
'firefox'
>>> request.user_agent.platform
'macos'
>>> request.user_agent.version
'3.1'
>>> request.user_agent.language
'en-US'
~~~
一個更有用的 headers 是 Accept header。這個 header 將會告訴 web 應用可以處理并怎么處理MIME類型,所有 accept header 被嚴格分類,最重要的是第一條:
~~~
>>> 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
~~~
E-tags 和其他條件 header 也可以被解析:
~~~
>>> request.if_modified_since
datetime.datetime(2009, 2, 20, 10, 10, 25)
>>> 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
~~~
### Response
Response 對象和請求對象相對。他常用于向客戶端發送響應數據。實際上,在 WSGI 應用中沒有什么比 Response 對象更重要了。
那么你要做的不是從一個 WSGI 應用中返回 *returning* 響應對象,而是在 WSGI 應用內部調用一個 WSGI 應用并返回調用的值。
想象一個標準的 “Hello World” WSGI 應用:
~~~
def application(environ, start_res ponse):
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World!']
~~~
帶著一個響應對象的將會是這樣的:
~~~
from werkzeug.wrappers import Response
def application(environ, s tart_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 ,他們相互對應的。
同時常見的 headers 是公開的,可以作為屬性訪問或者用方法設置/獲取他們:
~~~
>>> response.content_length
12
>>> from datetime import datetime
>>> response.date = datetime(2009, 2, 20, 17, 42, 51)
>>> response.headers['Date']
'Fri, 20 Feb 2009 17:42:51 GMT'
~~~
因為 etags 可以使 weak 或者 strong,所以這里有方法可以設置它:
~~~
>>> 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)
~~~
一些有用的 headers 是可變的結構,比如 Content- header 是一個值的集合:
~~~
>>> response.content_language.add('en-us')
>>> response.content_language.add('en')
>>> response.headers['Content-Language']
'en-us, en'
~~~
下面的 header 值同樣不是單一的:
~~~
>>> response.headers['Content-Language'] = 'de-AT, de'
>>> response.content_language
HeaderSet(['de-AT', 'de'])
~~~
認證 header 也可以這樣設置:
~~~
>>> response.www_authenticate.set_basic("My protected resource")
>>> response.headers['www-authenticate']
'Basic realm="My protected resource"'
~~~
Cookie 同樣可以被設置:
~~~
>>> response.set_cookie('name', 'value')
>>> response.headers['Set-Cookie']
'name=value; Path=/'
>>> response.set_cookie('name2', 'value2')
~~~
如果頭出現多次,你可以使用 getlist() 方法來獲取一個 header 的所有值:
~~~
>>> response.headers.getlist('Set-Cookie')
['name=value; Path=/', 'name2=value2; Path=/']
~~~
最后如果你已經設置了所有條件值,那么你可以根據一個請求作出響應。這意味著,如果一個請求可以確定已經有了一個信息,只發送一個 header 是很節省流量的。盡管如此,你仍然應該至少設置一個 etag (用于比較) 和可以被請求對象的 make_conditional處理的 header 。
因此,響應是被改進的 (比如狀態碼改變,移除響應主題,刪除實體報頭等)。
- 開始
- Werkzeug 文檔概覽
- 安裝
- 過渡到 Werkzeug 1.0
- Werkzeug 教程
- API 標準
- 快速開始
- Python 3 Notes
- 服務和測試
- Debugging Applications
- 在服務器運行 WSGI 應用
- 單元測試
- 參考
- Request / Response Objects
- URL Routing
- WSGI Helpers
- HTTP Utilities
- Data Structures
- Utilities
- Context Locals
- Middlewares
- HTTP Exceptions
- 部署
- CGI
- mod_wsgi (Apache)
- FastCGI
- HTTP Proxying
- 貢獻模塊
- Atom Syndication
- Sessions
- Secure Cookie
- Cache
- Extra Wrappers
- Iter IO
- Fixers
- WSGI Application Profiler
- Lint Validation Middleware
- 額外說明
- Werkzeug Changelog
- Important Terms
- Unicode
- Dealing with Request Data