国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Python > 正文

Python WSGI的深入理解

2020-01-04 14:51:34
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

前言

本文主要介紹的是Python WSGI相關(guān)內(nèi)容,主要來(lái)自以下網(wǎng)址:

可以看成一次簡(jiǎn)單粗暴的翻譯。

什么是WSGI

WSGI的全稱是Web Server Gateway Interface,這是一個(gè)規(guī)范,描述了web server如何與web application交互、web application如何處理請(qǐng)求。該規(guī)范的具體描述在PEP 3333。注意,WSGI既要實(shí)現(xiàn)web server,也要實(shí)現(xiàn)web application。

實(shí)現(xiàn)了WSGI的模塊/庫(kù)有wsgiref(python內(nèi)置)、werkzeug.servingtwisted.web等,具體可見(jiàn)Servers which support WSGI

當(dāng)前運(yùn)行在WSGI之上的web框架有Bottle、Flask、Django等,具體可見(jiàn)Frameworks that run on WSGI

WSGI server所做的工作僅僅是將從客戶端收到的請(qǐng)求傳遞給WSGI application,然后將WSGI application的返回值作為響應(yīng)傳給客戶端。WSGI applications 可以是棧式的,這個(gè)棧的中間部分叫做中間件,兩端是必須要實(shí)現(xiàn)的application和server。

WSGI教程

這部分內(nèi)容主要來(lái)自WSGI Tutorial

WSGI application接口

WSGI application接口應(yīng)該實(shí)現(xiàn)為一個(gè)可調(diào)用對(duì)象,例如函數(shù)、方法、類(lèi)、含__call__方法的實(shí)例。這個(gè)可調(diào)用對(duì)象可以接收2個(gè)參數(shù):

  • 一個(gè)字典,該字典可以包含了客戶端請(qǐng)求的信息以及其他信息,可以認(rèn)為是請(qǐng)求上下文,一般叫做environment(編碼中多簡(jiǎn)寫(xiě)為environ、env);
  • 一個(gè)用于發(fā)送HTTP響應(yīng)狀態(tài)(HTTP status )、響應(yīng)頭(HTTP headers)的回調(diào)函數(shù)。

同時(shí),可調(diào)用對(duì)象的返回值是響應(yīng)正文(response body),響應(yīng)正文是可迭代的、并包含了多個(gè)字符串。

WSGI application結(jié)構(gòu)如下:

def application (environ, start_response): response_body = 'Request method: %s' % environ['REQUEST_METHOD'] # HTTP響應(yīng)狀態(tài) status = '200 OK' # HTTP響應(yīng)頭,注意格式 response_headers = [  ('Content-Type', 'text/plain'),  ('Content-Length', str(len(response_body))) ] # 將響應(yīng)狀態(tài)和響應(yīng)頭交給WSGI server start_response(status, response_headers) # 返回響應(yīng)正文 return [response_body]

Environment

下面的程序可以將environment字典的內(nèi)容返回給客戶端(environment.py):

# ! /usr/bin/env python# -*- coding: utf-8 -*- # 導(dǎo)入python內(nèi)置的WSGI serverfrom wsgiref.simple_server import make_serverdef application (environ, start_response): response_body = [  '%s: %s' % (key, value) for key, value in sorted(environ.items()) ] response_body = '/n'.join(response_body) # 由于下面將Content-Type設(shè)置為text/plain,所以`/n`在瀏覽器中會(huì)起到換行的作用 status = '200 OK' response_headers = [  ('Content-Type', 'text/plain'),  ('Content-Length', str(len(response_body))) ] start_response(status, response_headers) return [response_body]# 實(shí)例化WSGI serverhttpd = make_server ( '127.0.0.1',  8051, # port application # WSGI application,此處就是一個(gè)函數(shù))# handle_request函數(shù)只能處理一次請(qǐng)求,之后就在控制臺(tái)`print 'end'`了httpd.handle_request()print 'end'

瀏覽器(或者curl、wget等)訪問(wèn)http://127.0.0.1:8051/,可以看到environment的內(nèi)容。

另外,瀏覽器請(qǐng)求一次后,environment.py就結(jié)束了,程序在終端中輸出內(nèi)容如下:

127.0.0.1 - - [09/Sep/2015 23:39:09] "GET / HTTP/1.1" 200 5540
end

可迭代的響應(yīng)

如果把上面的可調(diào)用對(duì)象application的返回值:

return [response_body]

改成:

return response_body

這會(huì)導(dǎo)致WSGI程序的響應(yīng)變慢。原因是字符串response_body也是可迭代的,它的每一次迭代只能得到1 byte的數(shù)據(jù)量,這也意味著每一次只向客戶端發(fā)送1 byte的數(shù)據(jù),直到發(fā)送完畢為止。所以,推薦使用return [response_body]。

如果可迭代響應(yīng)含有多個(gè)字符串,那么Content-Length應(yīng)該是這些字符串長(zhǎng)度之和:

# ! /usr/bin/env python# -*- coding: utf-8 -*- from wsgiref.simple_server import make_serverdef application(environ, start_response): response_body = [  '%s: %s' % (key, value) for key, value in sorted(environ.items()) ] response_body = '/n'.join(response_body) response_body = [  'The Beggining/n',  '*' * 30 + '/n',  response_body,  '/n' + '*' * 30 ,  '/nThe End' ] # 求Content-Length content_length = sum([len(s) for s in response_body]) status = '200 OK' response_headers = [  ('Content-Type', 'text/plain'),  ('Content-Length', str(content_length)) ] start_response(status, response_headers) return response_bodyhttpd = make_server('localhost', 8051, application)httpd.handle_request()print 'end'

解析GET請(qǐng)求

運(yùn)行environment.py,在瀏覽器中訪問(wèn)http://localhost:8051/?age=10&hobbies=software&hobbies=tunning,可以在響應(yīng)的內(nèi)容中找到:

QUERY_STRING: age=10&hobbies=software&hobbies=tunningREQUEST_METHOD: GET

cgi.parse_qs()函數(shù)可以很方便的處理QUERY_STRING,同時(shí)需要cgi.escape()處理特殊字符以防止腳本注入,下面是個(gè)例子:

# ! /usr/bin/env python# -*- coding: utf-8 -*- from cgi import parse_qs, escapeQUERY_STRING = 'age=10&hobbies=software&hobbies=tunning'd = parse_qs(QUERY_STRING)print d.get('age', [''])[0] # ['']是默認(rèn)值,如果在QUERY_STRING中沒(méi)找到age則返回默認(rèn)值print d.get('hobbies', [])print d.get('name', ['unknown'])print 10 * '*'print escape('<script>alert(123);</script>')

輸出如下:

10
['software', 'tunning']
['unknown']
**********
<script>alert(123);</script>

然后,我們可以寫(xiě)一個(gè)基本的處理GET請(qǐng)求的動(dòng)態(tài)網(wǎng)頁(yè)了:

# ! /usr/bin/env python# -*- coding: utf-8 -*- from wsgiref.simple_server import make_serverfrom cgi import parse_qs, escape# html中form的method是get,action是當(dāng)前頁(yè)面html = """<html><body> <form method="get" action="">  <p>   Age: <input type="text" name="age" value="%(age)s">  </p>  <p>   Hobbies:   <input    name="hobbies" type="checkbox" value="software"    %(checked-software)s   > Software   <input    name="hobbies" type="checkbox" value="tunning"    %(checked-tunning)s   > Auto Tunning  </p>  <p>   <input type="submit" value="Submit">  </p> </form> <p>  Age: %(age)s<br>  Hobbies: %(hobbies)s </p></body></html>"""def application (environ, start_response): # 解析QUERY_STRING d = parse_qs(environ['QUERY_STRING']) age = d.get('age', [''])[0] # 返回age對(duì)應(yīng)的值 hobbies = d.get('hobbies', []) # 以list形式返回所有的hobbies # 防止腳本注入 age = escape(age) hobbies = [escape(hobby) for hobby in hobbies] response_body = html % {   'checked-software': ('', 'checked')['software' in hobbies],  'checked-tunning': ('', 'checked')['tunning' in hobbies],  'age': age or 'Empty',  'hobbies': ', '.join(hobbies or ['No Hobbies?']) } status = '200 OK' # 這次的content type是text/html response_headers = [  ('Content-Type', 'text/html'),  ('Content-Length', str(len(response_body))) ] start_response(status, response_headers) return [response_body]httpd = make_server('localhost', 8051, application)# 能夠一直處理請(qǐng)求httpd.serve_forever()print 'end'

啟動(dòng)程序,在瀏覽器中訪問(wèn)http://localhost:8051/、http://localhost:8051/?age=10&hobbies=software&hobbies=tunning感受一下~

這個(gè)程序會(huì)一直運(yùn)行,可以使用快捷鍵Ctrl-C終止它。

這段代碼涉及兩個(gè)我個(gè)人之前沒(méi)用過(guò)的小技巧:

>>> "Age: %(age)s" % {'age':12}'Age: 12'>>> >>> hobbies = ['software']>>> ('', 'checked')['software' in hobbies]'checked'>>> ('', 'checked')['tunning' in hobbies]''

解析POST請(qǐng)求

對(duì)于POST請(qǐng)求,查詢字符串(query string)是放在HTTP請(qǐng)求正文(request body)中的,而不是放在URL中。請(qǐng)求正文在environment字典變量中鍵wsgi.input對(duì)應(yīng)的值中,這是一個(gè)類(lèi)似file的變量,這個(gè)值是一個(gè)。The PEP 3333 指出,請(qǐng)求頭中CONTENT_LENGTH字段表示正文的大小,但是可能為空、或者不存在,所以讀取請(qǐng)求正文時(shí)候要用try/except。

下面是一個(gè)可以處理POST請(qǐng)求的動(dòng)態(tài)網(wǎng)站:

# ! /usr/bin/env python# -*- coding: utf-8 -*- from wsgiref.simple_server import make_serverfrom cgi import parse_qs, escape# html中form的method是posthtml = """<html><body> <form method="post" action="">  <p>   Age: <input type="text" name="age" value="%(age)s">  </p>  <p>   Hobbies:   <input    name="hobbies" type="checkbox" value="software"    %(checked-software)s   > Software   <input    name="hobbies" type="checkbox" value="tunning"    %(checked-tunning)s   > Auto Tunning  </p>  <p>   <input type="submit" value="Submit">  </p> </form> <p>  Age: %(age)s<br>  Hobbies: %(hobbies)s </p></body></html>"""def application(environ, start_response): # CONTENT_LENGTH 可能為空,或者沒(méi)有 try:  request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError):  request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) d = parse_qs(request_body) # 獲取數(shù)據(jù) age = d.get('age', [''])[0]  hobbies = d.get('hobbies', [])  # 轉(zhuǎn)義,防止腳本注入 age = escape(age) hobbies = [escape(hobby) for hobby in hobbies] response_body = html % {   'checked-software': ('', 'checked')['software' in hobbies],  'checked-tunning': ('', 'checked')['tunning' in hobbies],  'age': age or 'Empty',  'hobbies': ', '.join(hobbies or ['No Hobbies?']) } status = '200 OK' response_headers = [  ('Content-Type', 'text/html'),  ('Content-Length', str(len(response_body))) ] start_response(status, response_headers) return [response_body]httpd = make_server('localhost', 8051, application)httpd.serve_forever()print 'end' 

Python WSGI入門(mén)

這段內(nèi)容參考自An Introduction to the Python Web Server Gateway Interface (WSGI) 

Web server

WSGI server就是一個(gè)web server,其處理一個(gè)HTTP請(qǐng)求的邏輯如下:

iterable = app(environ, start_response)for data in iterable: # send data to client

app即WSGI application,environ即上文中的environment。可調(diào)用對(duì)象app返回一個(gè)可迭代的值,WSGI server獲得這個(gè)值后將數(shù)據(jù)發(fā)送給客戶端。

Web framework/app

即WSGI application。

中間件(Middleware)

中間件位于WSGI server和WSGI application之間,所以

一個(gè)示例

該示例中使用了中間件。

# ! /usr/bin/env python# -*- coding: utf-8 -*- from wsgiref.simple_server import make_serverdef application(environ, start_response): response_body = 'hello world!' status = '200 OK' response_headers = [  ('Content-Type', 'text/plain'),  ('Content-Length', str(len(response_body))) ] start_response(status, response_headers) return [response_body]# 中間件class Upperware: def __init__(self, app):  self.wrapped_app = app def __call__(self, environ, start_response):  for data in self.wrapped_app(environ, start_response):  yield data.upper()wrapped_app = Upperware(application)httpd = make_server('localhost', 8051, wrapped_app)httpd.serve_forever()print 'end'

然后

有了這些基礎(chǔ)知識(shí),就可以打造一個(gè)web框架了。感興趣的話,可以閱讀一下Bottle、Flask等的源碼。

Learn about WSGI還有更多關(guān)于WSGI的內(nèi)容。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)VEVB武林網(wǎng)的支持。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到python教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宝坻区| 武平县| 万宁市| 凤城市| 历史| 贡觉县| 墨玉县| 泉州市| 云浮市| 井陉县| 黎平县| 盐边县| 浠水县| 莆田市| 涿鹿县| 兴山县| 白山市| 安顺市| 视频| 内黄县| 合作市| 临汾市| 泾阳县| 称多县| 平顺县| 兴安盟| 独山县| 贡嘎县| 赫章县| 柘城县| 弥渡县| 阜康市| 舟曲县| 莒南县| 镇宁| 宁明县| 盘锦市| 禹城市| 眉山市| 宁夏| 古浪县|