Python 的 Requests 函式庫簡化了 HTTP 請求的處理流程,其靈活的 Cookie 建立機制允許開發者透過關鍵字引數自定義 Cookie 屬性。狀態碼查詢字典則提供可讀性更高的狀態碼存取方式,提升程式碼維護性。Werkzeug 作為 WSGI 工具箱,提供 URL 路由、HTTP 標頭處理、請求/回應物件等功能,簡化 WSGI 應用程式開發。其路由系統根據 Map 和 Rule 兩個核心類別,能有效管理和匹配路由規則。此外,Werkzeug 還支援自定義轉換器,可處理特定格式的 URL 引數,並透過 Tox 進行跨 Python 版本的測試,確保程式碼的相容性。
Requests 函式庫中的 Cookie 建立與狀態碼處理
Cookie 建立的靈活性與錯誤處理
在 Requests 函式庫中,create_cookie() 函式負責建立 Cookie 物件。該函式透過 **kwargs 允許使用者提供任意或不提供關鍵字選項來建立 Cookie。以下為具體實作:
result = dict(
version=0,
name=name,
value=value,
port=None,
domain='',
path='/',
secure=False,
expires=None,
discard=True,
comment=None,
comment_url=None,
rest={'HttpOnly': None},
rfc2109=False,
)
badargs = set(kwargs) - set(result)
if badargs:
err = 'create_cookie() got unexpected keyword arguments: %s'
raise TypeError(err % list(badargs))
result.update(kwargs)
result['port_specified'] = bool(result['port'])
result['domain_specified'] = bool(result['domain'])
result['domain_initial_dot'] = result['domain'].startswith('.')
result['path_specified'] = bool(result['path'])
return cookielib.Cookie(**result)
內容解密:
result字典初始化:預設建立一個包含 Cookie 屬性的字典,涵蓋大部分常見的 Cookie 屬性。- 錯誤處理:檢查
kwargs中是否有未預期的關鍵字引數,若有則丟出TypeError例外。 result.update(kwargs):將使用者提供的額外引數更新至result字典中,既可替換現有屬性,也可新增屬性。- 布林值轉換:將特定屬性(如
port、domain、path)轉換為布林值,以表示是否已指定這些屬性。 - 建立
cookielib.Cookie物件:利用更新後的result字典,以關鍵字引數的形式建立並傳回cookielib.Cookie物件。
狀態碼查詢字典的設計與應用
Requests 函式庫中的 status_codes.py 檔案定義了一個狀態碼查詢字典 _codes,用於將 HTTP 狀態碼對映到可讀的屬性名稱。以下是範例程式碼:
_codes = {
# 資訊回應
100: ('continue',),
101: ('switching_protocols',),
# ...
200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', ''),
# ...
}
codes = LookupDict(name='status_codes')
for code, titles in _codes.items():
for title in titles:
setattr(codes, title, code)
if not title.startswith('\\'):
setattr(codes, title.upper(), code)
內容解密:
_codes字典定義:將 HTTP 狀態碼對映到多個屬性名稱,例如將200對映到('ok', 'okay', ...)。LookupDict物件建立:建立一個名為codes的LookupDict物件,用於儲存狀態碼及其對應的屬性名稱。- 動態屬性設定:透過迴圈遍歷
_codes,為codes物件動態設定屬性,使得狀態碼可以透過可讀的屬性名稱存取。 - 大小寫支援:除了設定原始屬性名稱外,還為不包含特殊字元的屬性名稱設定大寫版本,以增強靈活性。
狀態碼在重定向處理中的應用
在 sessions.py 中,狀態碼查詢字典被用於處理 HTTP 重定向。範例如下:
from .status_codes import codes
class SessionRedirectMixin(object):
def resolve_redirects(self, resp, req, stream=False, timeout=None,
verify=True, cert=None, proxies=None,
**adapter_kwargs):
# ...
if resp.status_code == codes.see_other and method != 'HEAD':
method = 'GET'
if resp.status_code == codes.found and method != 'HEAD':
method = 'GET'
if resp.status_code == codes.moved and method == 'POST':
method = 'GET'
# ...
內容解密:
- 狀態碼查詢:使用
codes.see_other、codes.found和codes.moved等可讀屬性名稱來檢查 HTTP 狀態碼,使程式碼更具可讀性。 - 重定向邏輯處理:根據不同的狀態碼和請求方法,調整請求方法(如將 POST 改為 GET),以符合瀏覽器的行為標準。
- 程式碼可讀性提升:相較於直接使用數值狀態碼,使用具描述性的屬性名稱(如
codes.see_other代表303)能大幅提升程式碼的可讀性和維護性。
Werkzeug:WSGI工具箱的設計與實作
Werkzeug是一個用於建立WSGI應用程式和中介軟體元件的Python函式庫。它提供了許多實用的工具和類別,使得開發WSGI應用程式變得更加容易。
WSGI簡介
WSGI(Web Server Gateway Interface)是Python應用程式與Web伺服器之間的介面標準。它定義了伺服器如何呼叫應用程式,以及應用程式如何回傳回應給伺服器。WSGI標準在PEP 333中定義,並在PEP 3333中更新以支援Python 3。
WSGI的主要特點
- 伺服器呼叫應用程式:伺服器會為每個HTTP請求呼叫一次應用程式。
- 應用程式回傳回應:應用程式會回傳一個可迭代的位元組字串,伺服器會使用它來回應HTTP請求。
- 應用程式引數:應用程式會接收兩個引數:
environ和start_response。environ包含了請求的相關資料,而start_response是一個可呼叫的物件,用於傳送標頭和狀態資訊給伺服器。
Werkzeug的設計與實作
Werkzeug由Armin Ronacher在2007年釋出,旨在滿足對WSGI函式庫的需求。Werkzeug提供了許多實用的工具和類別,包括:
- WSGI 1.0實作:Werkzeug實作了WSGI 1.0標準(PEP 333)。
- URL路由系統:Werkzeug提供了URL路由系統,使得處理HTTP請求變得更加容易。
- HTTP標頭解析和轉儲:Werkzeug可以解析和轉儲HTTP標頭。
- HTTP請求和回應物件:Werkzeug提供了代表HTTP請求和回應的物件。
- 工作階段和Cookie支援:Werkzeug支援工作階段和Cookie。
- 檔案上傳:Werkzeug支援檔案上傳。
使用Werkzeug
要使用Werkzeug,我們可以從一個簡單的WSGI應用程式開始:
def wsgi_app(environ, start_response):
headers = [('Content-type', 'text/plain'), ('charset', 'utf-8')]
start_response('200 OK', headers)
yield 'Hello world.'
內容解密:
此段程式碼定義了一個簡單的WSGI應用程式。它接收environ和start_response兩個引數,並使用start_response傳送標頭和狀態資訊給伺服器。然後,它回傳一個可迭代的位元組字串,包含字串"Hello world."。
我們可以使用Werkzeug的Response類別來簡化這個過程:
response_app = werkzeug.Response('Hello world!')
內容解密:
此段程式碼使用Werkzeug的Response類別建立了一個WSGI應用程式。它等同於前面的例子,但更加簡潔。
Werkzeug還提供了Client類別,用於測試WSGI應用程式:
client = werkzeug.Client(wsgi_app, response_wrapper=werkzeug.Response)
resp = client.get("?answer=42")
print(resp.data.decode())
內容解密:
此段程式碼使用Werkzeug的Client類別建立了一個測試客戶端。它呼叫了前面定義的WSGI應用程式,並列印出回應的內容。
Werkzeug的優勢
Werkzeug提供了許多實用的工具和類別,使得開發WSGI應用程式變得更加容易。它的優勢包括:
- 簡化WSGI應用程式開發:Werkzeug提供了許多實用的工具和類別,簡化了WSGI應用程式的開發。
- 提高開發效率:Werkzeug的工具和類別可以提高開發效率,減少開發時間。
Werkzeug 路由系統深度解析
Werkzeug 是 Python 中一個強大的 Web 開發工具函式庫,其路由系統是其核心功能之一。本文將探討 Werkzeug 的路由機制,並透過例項演示其用法。
路由基礎
Werkzeug 的路由系統根據 Map 和 Rule 兩個主要類別。Map 用於管理多個路由規則,而 Rule 則定義了單一路由規則。
from werkzeug.routing import Map, Rule
url_map = Map([
Rule('/', endpoint='index'),
Rule('/<any("Robin","Galahad","Arthur"):person>', endpoint='ask'),
Rule('/<other>', endpoint='other')
])
內容解密:
Map類別用於建立路由表,管理多個Rule例項。Rule類別定義單一路由規則,包括路徑模式和對應的端點(endpoint)。<any("Robin","Galahad","Arthur"):person>是一種特殊的路徑引數,限制person只能是 “Robin”、“Galahad” 或 “Arthur” 三者之一。- endpoint 是一個字串,用於標識路由對應的處理函式或檢視。
路由匹配
當請求到達時,Werkzeug 會使用 Map 例項來匹配對應的路由規則。
env = werkzeug.create_environ(path='/Galahad')
urls = url_map.bind_to_environ(env)
endpoint, kwargs = urls.match()
內容解密:
create_environ函式建立一個模擬的 WSGI 環境。bind_to_environ方法將Map例項繫結到特定的 WSGI 環境,建立一個MapAdapter例項。match方法嘗試匹配路由規則,如果成功傳回 endpoint 和引數字典;否則丟擲NotFound異常。
路由應用
將路由機制應用於實際的 Web 應用中,需要將請求分派到對應的端點處理函式。
@werkzeug.Request.application
def send_to_endpoint(request):
urls = url_map.bind_to_environ(request.environ)
try:
endpoint, kwargs = urls.match()
if endpoint == 'index':
return werkzeug.Response("You got the index.")
elif endpoint == 'ask':
questions = {
'Galahad': 'What is your favorite color?',
'Robin': 'What is the capital of Assyria?',
'Arthur': 'What is the air-speed velocity of an unladen swallow?'
}
return werkzeug.Response(questions[kwargs['person']])
else:
return werkzeug.Response(f"Other: {kwargs['other']}")
except Exception as e:
return werkzeug.Response('You may not have gone where you intended to go,\nbut I think you have ended up where you needed to be.', status=404)
內容解密:
- 使用
@werkzeug.Request.application裝飾器將send_to_endpoint函式轉換為 WSGI 應用。 - 在函式內部,將請求環境繫結到
url_map,並嘗試匹配路由。 - 根據匹配結果,分派到不同的處理邏輯,並傳回相應的回應。
- 使用 try-except 塊捕捉異常,傳回自定義的 404 回應。
測試路由應用
使用 werkzeug.Client 可以方便地測試 WSGI 應用。
client = werkzeug.Client(send_to_endpoint, response_wrapper=werkzeug.Response)
print(client.get("/").data.decode())
print(client.get("/Arthur").data.decode())
print(client.get("/42").data.decode())
內容解密:
werkzeug.Client用於模擬客戶端請求。get方法傳送 GET 請求到指定的路徑。data.decode()用於取得回應內容並解碼為字串。
Werkzeug 原始碼閱讀與技術解析
Werkzeug 是一個功能強大的 Python 函式庫,主要用於 Web 應用程式的開發。透過閱讀其原始碼,可以深入瞭解其內部實作機制和設計理念。
測試案例與功能展示
Werkzeug 的測試案例展示了其豐富的功能和靈活性。例如,在 test_wrappers.py 中,測試了 Request 物件的各種功能,包括 cookies、編碼、認證、安全性和快取逾時等。
def test_modified_url_encoding():
class ModifiedRequest(wrappers.Request):
url_charset = 'euc-kr'
req = ModifiedRequest.from_values(u'/?foo=정상처리'.encode('euc-kr'))
strict_eq(req.args['foo'], u'정상처리')
內容解密:
此測試案例展示瞭如何自定義 Request 物件的 URL 編碼方式。在這個例子中,將 url_charset 設定為 ’euc-kr’,並測試了是否能夠正確解析韓文字元。測試結果驗證了 Werkzeug 在處理不同編碼時的靈活性。
路由模組的測試
Werkzeug 的路由模組提供了強大的 URL 路由功能。測試案例展示瞭如何使用非 ASCII 字元進行路由匹配。
def test_environ_nonascii_pathinfo():
environ = create_environ(u'/лошадь')
m = r.Map([
r.Rule(u'/', endpoint='index'),
r.Rule(u'/лошадь', endpoint='horse')
])
a = m.bind_to_environ(environ)
strict_eq(a.match(u'/'), ('index', {}))
strict_eq(a.match(u'/лошадь'), ('horse', {}))
pytest.raises(r.NotFound, a.match, u'/барсук')
內容解密:
此測試案例驗證了 Werkzeug 在處理非 ASCII 字元的 URL 時的正確性。首先,建立了一個包含非 ASCII 字元的 WSGI 環境變數。然後,定義了一個路由對映,包含兩個路由規則。接著,將路由對映繫結到環境變數,並進行路由匹配測試。測試結果表明,Werkzeug 能夠正確匹配包含非 ASCII 字元的 URL。
自定義轉換器
Werkzeug 允許開發者自定義轉換器,以處理特定的 URL 引數。
class TwoValueConverter(r.BaseConverter):
def __init__(self, *args, **kwargs):
super(TwoValueConverter, self).__init__(*args, **kwargs)
self.regex = r'(\w\w+)/(\w\w+)'
def to_python(self, two_values):
one, two = two_values.split('/')
return one, two
def to_url(self, values):
return "%s/%s" % (values[0], values[1])
內容解密:
此自定義轉換器 TwoValueConverter 用於處理形如 ‘xx/xx’ 的 URL 引數。它繼承自 r.BaseConverter,並重寫了 __init__、to_python 和 to_url 方法。在 __init__ 方法中,設定了正規表示式以匹配 ‘xx/xx’ 的格式。在 to_python 方法中,將匹配到的字串分割成兩個部分,並傳回一個元組。在 to_url 方法中,將輸入的元組格式化成 ‘xx/xx’ 的字串。
Tox 組態檔案解析
Werkzeug 使用 Tox 進行跨多個 Python 版本的測試。其 tox.ini 組態檔案定義了測試環境和依賴項。
[tox]
envlist = py{26,27,py,33,34,35}-normal, py{26,27,33,34,35}-uwsgi
[testenv]
passenv = LANG
deps=
# General
pyopenssl
greenlet
pytest
pytest-xprocess
redis
requests
watchdog
uwsgi: uwsgi
內容解密:
此組態檔案指定了測試環境的列表,包括多個 Python 版本。passenv 用於傳遞環境變數 LANG 到測試環境中。deps 部分列出了測試所需的依賴項,包括通用依賴和特定 Python 版本的依賴。這些依賴項確保了測試能夠在不同的環境中正確執行。