摘要:在介紹之前,先介紹一下,它為語(yǔ)言定義的服務(wù)器和應(yīng)用程序或框架之間的一種簡(jiǎn)單而通用的接口。這個(gè)函數(shù)接受兩個(gè)參數(shù),分別是和。響應(yīng)對(duì)象是一個(gè)應(yīng)用,提供了更好的方法來(lái)創(chuàng)建響應(yīng)。這部分解釋來(lái)源于官方文檔的中文版。
Werkzeug 是一個(gè)WSGI工具包,也可以作為一個(gè)Web框架的底層庫(kù)。
WSGI在介紹Werkzeug之前,先介紹一下 WSGI(Python Web Server Gateway Interface),它為Python語(yǔ)言定義的Web服務(wù)器和Web應(yīng)用程序或框架之間的一種簡(jiǎn)單而通用的接口。這是一個(gè)規(guī)范,描述了web server如何與web application交互、web application如何處理請(qǐng)求,該規(guī)范的具體描述在PEP3333,強(qiáng)烈推薦先閱讀 PEP3333 再回頭來(lái)閱讀本文。
WSGI 分為兩個(gè)部分:
Server/Gateway: 即是HTTP Server, 負(fù)責(zé)從客戶端(Nginx、apache、IIS)接收請(qǐng)求,將 request 轉(zhuǎn)發(fā)給 application, 并將 application(可能是個(gè)Flask應(yīng)用) 返回的response 返回給客戶端
Application/Framework: 一個(gè)python web 應(yīng)用或 web 框架接收由 server 轉(zhuǎn)發(fā)的request,處理請(qǐng)求,并將處理結(jié)果返回給 server
可以通過(guò)下面兩張圖片來(lái)梳理一下它們之間的調(diào)用關(guān)系:
先從一份示例代碼理解:
def application(environ, start_response): start_response("200 OK", [("Content-Type", "text/plain")]) return ["Hello World!"]
一個(gè)最基本的 WSGI 應(yīng)用就是如上所示,定義了一個(gè) application 函數(shù)(callable object),callable object(可調(diào)用對(duì)象) 包括: 一個(gè)函數(shù)、方法、類或一個(gè)實(shí)現(xiàn)了__call__的實(shí)例都可以用作應(yīng)用程序?qū)ο?。這個(gè)函數(shù)接受兩個(gè)參數(shù),分別是environ和start_response。
environ是一個(gè)字典包含了CGI中的環(huán)境變量
start_response也是一個(gè)callable,接受兩個(gè)必須的參數(shù),status(HTTP狀態(tài))和response_headers(響應(yīng)消息的頭)
通過(guò)回調(diào)函數(shù)(start_response)將響應(yīng)狀態(tài)和響應(yīng)頭返回給 server,同時(shí)返回響應(yīng)正文(response body),響應(yīng)正文是可迭代的、并包含了多個(gè)字符串。
Werkzeugwerkzeug 提供了 python web WSGI 開發(fā)相關(guān)的功能:
路由處理:如何根據(jù)請(qǐng)求 URL 找到對(duì)應(yīng)的視圖函數(shù)
request 和 response 封裝: 提供更好的方式處理request和生成response對(duì)象
自帶的 WSGI server: 測(cè)試環(huán)境運(yùn)行WSGI應(yīng)用
下面使用 Werkzeug 來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的WSGI應(yīng)用:
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)
如上代碼所示,請(qǐng)求數(shù)據(jù)需要環(huán)境對(duì)象,Werkzeug允許你以一個(gè)輕松的方式訪問數(shù)據(jù)。響應(yīng)對(duì)象是一個(gè) WSGI 應(yīng)用,提供了更好的方法來(lái)創(chuàng)建響應(yīng)。
具體創(chuàng)建一個(gè) WSGI 應(yīng)用請(qǐng)查看文檔,后面會(huì)陸續(xù)提到Flask框架中使用到Werkzeug的數(shù)據(jù)結(jié)構(gòu)。這里貼一些官方文檔的例子,使用werkzeug創(chuàng)建一個(gè)web 應(yīng)用:
import os import redis import urlparse from werkzeug.wrappers import Request, Response from werkzeug.routing import Map, Rule from werkzeug.exceptions import HTTPException, NotFound from werkzeug.wsgi import SharedDataMiddleware from werkzeug.utils import redirect from jinja2 import Environment, FileSystemLoader class Shortly(object): """ Shortly 是一個(gè)實(shí)際的 WSGI 應(yīng)用,通過(guò) __call__ 方法直接調(diào) 用 wsgi_app, 同時(shí)通過(guò)一個(gè)可選設(shè)置創(chuàng)建一個(gè)中間件,將static文件夾暴露給用戶: """ def __init__(self, config): self.redis = redis.Redis(config["redis_host"], config["redis_port"]) def dispatch_request(self, request): return Response("Hello World!") def wsgi_app(self, environ, start_response): request = Request(environ) response = self.dispatch_request(request) return response(environ, start_response) def __call__(self, environ, start_response): return self. wsgi_app(environ, start_response) def create_app(redis_host="localhost", redis_port=6379, with_static=True): app = Shortly({ "redis_host": redis_host, "redis_port": redis_port }) if with_static: app.wsgi_app = SharedDataMiddleware(app.wsgi_app, { "/static": os.path.join(os.path.dirname(__file__), "static") }) return app if __name__ == "__main__": from werkzeug.serving import run_simple app = create_app() run_simple("127.0.0.1", 5000, app, use_debugger=True, use_reloader=True)
思路很簡(jiǎn)單,我們的 Shortly 是一個(gè)實(shí)際的 WSGI 應(yīng)用。 __call__ 方法直接調(diào)用 wsgi_app 。這樣做我們可以裝飾 wsgi_app 調(diào)用中間件,就像我們?cè)?create_app 函數(shù)中做的一樣。 wsgi_app 實(shí)際上創(chuàng)建了一個(gè) Request 對(duì)象,之后通過(guò) dispatch_request 調(diào)用 Request 對(duì)象然后給 WSGI 應(yīng)用返回一個(gè) Response 對(duì)象。正如你看到的:無(wú)論是創(chuàng)建 Shortly 類,還是創(chuàng)建 Werkzeug Request 對(duì)象來(lái)執(zhí)行 WSGI 接口。最終結(jié)果只是從 dispatch_request 方法返回另一個(gè) WSGI 應(yīng)用。這部分解釋來(lái)源于官方文檔的中文版。
總結(jié)本文主要解釋了WSGI規(guī)范和Werkzeug(WSGI 工具集),以及如何實(shí)現(xiàn)一個(gè)符合WSGI規(guī)范的WSGI應(yīng)用,最后使用Werkzeug 工具集中的相關(guān)模塊,快速實(shí)現(xiàn)了一個(gè)基于WSGI的簡(jiǎn)單應(yīng)用。
參考Werkzeug 中文文檔
Werkzeug 英文文檔
WSGI Servers
WSGI協(xié)議的原理和實(shí)現(xiàn)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/42491.html
摘要:本文就主要針對(duì)一個(gè)應(yīng)用的運(yùn)行過(guò)程進(jìn)行簡(jiǎn)要分析,后續(xù)文章還會(huì)對(duì)框架的一些具體問題進(jìn)行分析。所有的請(qǐng)求處理過(guò)程,都會(huì)在這個(gè)上下文對(duì)象中進(jìn)行。和一些全局變量注意當(dāng)進(jìn)入這個(gè)上下文對(duì)象時(shí),會(huì)觸發(fā)。 相信很多初學(xué)Flask的同學(xué)(包括我自己),在閱讀官方文檔或者Flask的學(xué)習(xí)資料時(shí),對(duì)于它的認(rèn)識(shí)是從以下的一段代碼開始的: from flask import Flask app = Flask(...
摘要:簡(jiǎn)介官網(wǎng)上對(duì)它的定位是一個(gè)微開發(fā)框架。另外一個(gè)必須理解的概念是,簡(jiǎn)單來(lái)說(shuō)就是一套和框架應(yīng)用之間的協(xié)議。功能比較豐富,支持解析自動(dòng)防止攻擊繼承變量過(guò)濾器流程邏輯支持代碼邏輯集成等等。那么,從下一篇文章,我們就正式開始源碼之旅了 文章屬于作者原創(chuàng),原文發(fā)布在個(gè)人博客。 flask 簡(jiǎn)介 Flask 官網(wǎng)上對(duì)它的定位是一個(gè)微 python web 開發(fā)框架。 Flask is a micro...
摘要:另外,如果你對(duì)模板渲染部分的內(nèi)容感興趣,也可以考慮閱讀文檔文檔文檔源碼閱讀,可以參考下面的函數(shù)打斷點(diǎn),再測(cè)試一個(gè)請(qǐng)求,理清過(guò)程。 Flask-Origin 源碼版本 一直想好好理一下flask的實(shí)現(xiàn),這個(gè)項(xiàng)目有Flask 0.1版本源碼并加了注解,挺清晰明了的,我在其基礎(chǔ)上完成了對(duì)Werkzeug的理解部分,大家如果想深入學(xué)習(xí)的話,可以參考werkzeug_flow.md. 閱讀前 為...
摘要:中有一個(gè)非常重要的概念每個(gè)應(yīng)用都是一個(gè)可調(diào)用的對(duì)象。它規(guī)定了的接口,會(huì)調(diào)用,并傳給它兩個(gè)參數(shù)包含了請(qǐng)求的所有信息,是處理完之后需要調(diào)用的函數(shù),參數(shù)是狀態(tài)碼響應(yīng)頭部還有錯(cuò)誤信息。一般來(lái)說(shuō),嵌套的最后一層是業(yè)務(wù)應(yīng)用,中間就是。 文章屬于作者原創(chuàng),原文發(fā)布在個(gè)人博客。 WSGI 所有的 python web 框架都要遵循 WSGI 協(xié)議,如果對(duì) WSGI 不清楚,可以查看我之前的介紹文章。 ...
摘要:具體怎么實(shí)現(xiàn)的呢,思想其實(shí)特別簡(jiǎn)單,我們?cè)谏钊肜斫庵械淖兞可弦晃牡淖詈笥刑崞疬^(guò),就是創(chuàng)建一個(gè)全局字典,然后將線程或者協(xié)程標(biāo)識(shí)符作為,相應(yīng)線程或協(xié)程的局部數(shù)據(jù)作為。 在上篇我們看到了 ThreadLocal 變量的簡(jiǎn)單使用,中篇對(duì)python中 ThreadLocal 的實(shí)現(xiàn)進(jìn)行了分析,但故事還沒有結(jié)束。本篇我們一起來(lái)看下Werkzeug中ThreadLocal的設(shè)計(jì)。 Werkzeug...
閱讀 2249·2023-04-25 19:06
閱讀 1446·2021-11-17 09:33
閱讀 1846·2019-08-30 15:53
閱讀 2655·2019-08-30 14:20
閱讀 3606·2019-08-29 12:58
閱讀 3612·2019-08-26 13:27
閱讀 577·2019-08-26 12:23
閱讀 549·2019-08-26 12:22