日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

WSGI

發(fā)布時(shí)間:2024/4/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WSGI 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

前言

本文不涉及WSGI的具體協(xié)議的介紹,也不會(huì)有協(xié)議完整的實(shí)現(xiàn),甚至描述中還會(huì)摻雜著本人自己對(duì)于WSGI的見解。所有的WSGI官方定義請(qǐng)看http://www.python.org/dev/peps/pep-3333/。

WSGI是什么?

WSGI的官方定義是,the Python Web Server Gateway Interface。從名字就可以看出來(lái),這東西是一個(gè)Gateway,也就是網(wǎng)關(guān)。網(wǎng)關(guān)的作用就是在協(xié)議之間進(jìn)行轉(zhuǎn)換。

也就是說(shuō),WSGI就像是一座橋梁,一邊連著web服務(wù)器,另一邊連著用戶的應(yīng)用。但是呢,這個(gè)橋的功能很弱,有時(shí)候還需要?jiǎng)e的橋來(lái)幫忙才能進(jìn)行處理。

下面對(duì)本文出現(xiàn)的一些名詞做定義。wsgi app,又稱應(yīng)用?,就是一個(gè)WSGI application。wsgi container ,又稱容器?,雖然這個(gè)部分常常被稱為handler,不過我個(gè)人認(rèn)為handler容易和app混淆,所以我稱之為容器。 wsgi_middleware ,又稱*中間件*。一種特殊類型的程序,專門負(fù)責(zé)在容器和應(yīng)用之間干壞事的。

一圖勝千言,直接來(lái)一個(gè)我自己理解的WSGI架構(gòu)圖吧

可以看出,服務(wù)器,容器和應(yīng)用之間存在著十分糾結(jié)的關(guān)系。下面就要把這些糾結(jié)的關(guān)系理清楚。

WSGI應(yīng)用

WSGI應(yīng)用其實(shí)就是一個(gè)callable的對(duì)象。舉一個(gè)最簡(jiǎn)單的例子,假設(shè)存在如下的一個(gè)應(yīng)用:

1def?application(environ, start_response):?
2??status?=?'200 OK'?
3??output?=?'World!'?
4??response_headers?=?[('Content-type',?'text/plain'),?
5??????????????????????('Content-Length',?str(12)]?
6??write?=?start_response(status, response_headers)?
7??write('Hello ')?
8??return?[output]

這個(gè)WSGI應(yīng)用簡(jiǎn)單的可以用簡(jiǎn)陋來(lái)形容,但是他的確是一個(gè)功能完整的WSGI應(yīng)用。只不過給人留下了太多的疑點(diǎn),environ是什么?start_response是什么?為什么可以同時(shí)用write和return來(lái)返回內(nèi)容?

對(duì)于這些疑問,不妨自己猜測(cè)一下他的作用。聯(lián)想到CGI,那么environ可能就是一系列的環(huán)境變量,用來(lái)表示HTTP請(qǐng)求的信息,比如說(shuō)method 之類的。start_response,可能是接受HTTP response頭信息,然后返回一個(gè)write函數(shù),這個(gè)write函數(shù)可以把HTTP response的body返回給客戶端。return自然是將HTTP response的body信息返回。不過這里的write和函數(shù)返回有什么區(qū)別?會(huì)不會(huì)是其實(shí)外圍默認(rèn)調(diào)用write對(duì)應(yīng)用返回值進(jìn)行處理?而且為什么 應(yīng)用的返回值是一個(gè)列表呢?說(shuō)明肯定存在一個(gè)對(duì)應(yīng)用執(zhí)行結(jié)果的迭代輸出過程。難道說(shuō)他隱含的支持iterator或者generator嗎?

等等,應(yīng)用執(zhí)行結(jié)果?一個(gè)應(yīng)用既然是一個(gè)函數(shù),說(shuō)明肯定有一個(gè)對(duì)象去執(zhí)行它,并且可以猜到,這個(gè)對(duì)象把environ和start_response傳給應(yīng)用,將應(yīng)用的返回結(jié)果輸出給客戶端。那么這個(gè)對(duì)象是什么呢?自然就是WSGI容器了。

WSGI容器

先說(shuō)說(shuō)WSGI容器的來(lái)源,其實(shí)這是我自己編造出來(lái)的一個(gè)概念。來(lái)源就是JavaServlet容器。我個(gè)人理解兩者有相似的地方,就順手拿過來(lái)用了。

WSGI容器的作用,就是構(gòu)建一個(gè)讓W(xué)SGI應(yīng)用成功執(zhí)行的環(huán)境。成功執(zhí)行,意味著需要傳入正確的參數(shù),以及正確處理返回的結(jié)果,還得把結(jié)果返回給客戶端。

所以,WSGI容器的工作流程大致就是,用webserver規(guī)定的通信方式,能從webserver獲得正確的request信息,封裝好,傳給WSGI應(yīng)用執(zhí)行,正確的返回response。

一般來(lái)說(shuō),WSGI容器必須依附于現(xiàn)有的webserver的技術(shù)才能實(shí)現(xiàn),比如說(shuō)CGI,FastCGI,或者是embed的模式。

下面利用CGI的方式編寫一個(gè)最簡(jiǎn)單的WSGI容器。關(guān)于WSGI容器的協(xié)議官方文檔并沒有具體的說(shuō)如何實(shí)現(xiàn),只是介紹了一些需要約束的東西。具體內(nèi)容看PEP3333中的協(xié)議。

01#!/usr/bin/python?
02#encoding:utf8?
03??
04import?cgi?
05import?cgitb?
06import?sys?
07import?os?
08??
09#Make the environ argument?
10environ?=?{}?
11environ['REQUEST_METHOD']?=?os.environ['REQUEST_METHOD']?
12environ['SCRIPT_NAME']?=?os.environ['SCRIPT_NAME']?
13environ['PATH_INFO']?=?os.environ['PATH_INFO']?
14environ['QUERY_STRING']?=?os.environ['QUERY_STRING']?
15environ['CONTENT_TYPE']?=?os.environ['CONTENT_TYPE']?
16environ['CONTENT_LENGTH']?=?os.environ['CONTENT_LENGTH']?
17environ['SERVER_NAME']?=?os.environ['SERVER_NAME']?
18environ['SERVER_PORT']?=?os.environ['SERVER_PORT']?
19environ['SERVER_PROTOCOL']?=?os.environ['SERVER_PROTOCOL']?
20environ['wsgi.version']?=?(1,?)?
21environ['wsgi.url_scheme']?=?'http'?
22environ['wsgi.input']????????=?sys.stdin?
23environ['wsgi.errors']???????=?sys.stderr?
24environ['wsgi.multithread']??=?False?
25environ['wsgi.multiprocess']?=?True?
26environ['wsgi.run_once']?????=?True?
27??
28??
29#make the start_response argument?
30#注意,WSGI協(xié)議規(guī)定,如果沒有body內(nèi)容,是不能返回http response頭信息的。?
31sent_header?=?False?
32res_status?=?None?
33res_headers?=?None?
34??
35def?write(body):?
36????global?sent_header?
37????if?sent_header:?
38????????sys.stdout.write(body)?
39????else:?
40????????print?res_status?
41????????for?k, v?in?res_headers:?
42????????????print?k?+?': '?+?v?
43????????print??
44????????sys.stdout.write(body)?
45????????sent_header?=?True?
46??
47def?start_response(status, response_headers):?
48????global?res_status?
49????global?res_headers?
50????res_status?=?status?
51????res_headers?=?response_headers?
52????return?write?
53??
54#here is the application?
55??def?application(environ, start_response):?
56????status?=?'200 OK'?
57????output?=?'World!'?
58????response_headers?=?[('Content-type',?'text/plain'),?
59????????????????????????('Content-Length',?str(12)]?
60????write?=?start_response(status, response_headers)?
61????write('Hello ')?
62????return?[output]?
63??
64#here run the application?
65result?=?application(environ, start_response)?
66for?value?in?result:??
67????write(value)

看吧。其實(shí)實(shí)現(xiàn)一個(gè)WSGI容器也不難。

不過我從WSGI容器的設(shè)計(jì)中可以看出WSGI的應(yīng)用設(shè)計(jì)上面存在著一個(gè)重大的問題就是:為什么要提供兩種方式返回?cái)?shù)據(jù)?明明只有一個(gè)write函數(shù),卻 既可以在application里面調(diào)用,又可以在容器中傳輸應(yīng)用的返回值來(lái)調(diào)用。如果說(shuō)讓我來(lái)設(shè)計(jì)的話,直接把start_response給去掉了。 就用application(environ)這個(gè)接口。傳一個(gè)方法,然后返回值就是status, response_headers和一個(gè)字符串的列表。實(shí)際傳輸?shù)姆椒ㄈ侩[藏了。用戶只需要從environ中讀取數(shù)據(jù)處理就行了。。

可喜的是,搜了一下貌似web3的標(biāo)準(zhǔn)里面應(yīng)用的設(shè)計(jì)和我的想法類似。希望web3協(xié)議能早日普及。

Middleware中間件

中間件是一類特殊的程序,可以在容器和應(yīng)用之間干一些壞事。。其實(shí)熟悉python的decorator的人就會(huì)發(fā)現(xiàn),這和decoraotr沒什么區(qū)別。

下面來(lái)實(shí)現(xiàn)一個(gè)route的簡(jiǎn)單middleware。

01class?Router(object):?
02????def?__init__(self):?
03????????self.path_info?=?{}?
04????def?route(self, environ, start_response):?
05????????application?=?self.path_info[environ['PATH_INFO']]?
06????????return?application(environ, start_response)?
07????def?__call__(self, path):?
08????????def?wrapper(application):?
09????????????self.path_info[path]?=?application?
10????????return?wrapper

這就是一個(gè)很簡(jiǎn)單的路由功能的middleware。將上面那段wsgi容器的代碼里面的應(yīng)用修改成如下:

01router?=?Router()?
02??
03#here is the application?
04@router('/hello')?
05def?hello(environ, start_response):?
06????status?=?'200 OK'?
07????output?=?'Hello'?
08????response_headers?=?[('Content-type',?'text/plain'),?
09????????????????????????('Content-Length',?str(len(output)))]?
10????write?=?start_response(status, response_headers)?
11????return?[output]?
12??
13@router('/world')?
14def?world(environ, start_response):?
15????status?=?'200 OK'?
16????output?=?'World!'?
17????response_headers?=?[('Content-type',?'text/plain'),?
18????????????????????????('Content-Length',?str(len(output)))]?
19????write?=?start_response(status, response_headers)?
20????return?[output]?
21#here run the application?
22result?=?router.route(environ, start_response)?
23for?value?in?result:??
24????write(value)

這樣,容器就會(huì)自動(dòng)的根據(jù)訪問的地址找到對(duì)應(yīng)的app執(zhí)行了。

延伸

寫著寫著,怎么越來(lái)越像一個(gè)框架了?看來(lái)Python開發(fā)框架真是簡(jiǎn)單。。

其實(shí)從另外一個(gè)角度去考慮。如果把a(bǔ)pplication當(dāng)作是一個(gè)運(yùn)算單元。利用middleware調(diào)控IO和運(yùn)算資源,那么利用WSGI組成一個(gè)分布式的系統(tǒng)。

轉(zhuǎn)載于:https://my.oschina.net/lvrplayer/blog/32659

總結(jié)

以上是生活随笔為你收集整理的WSGI的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。