91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python中WSGI有什么用

發布時間:2021-08-12 13:36:14 來源:億速云 閱讀:118 作者:小新 欄目:開發技術

這篇文章主要介紹了Python中WSGI有什么用,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

什么是WSGI

WSGI的全稱是Web Server Gateway Interface,這是一個規范,描述了web server如何與web application交互、web application如何處理請求。該規范的具體描述在PEP 3333。注意,WSGI既要實現web server,也要實現web application。

實現了WSGI的模塊/庫有wsgiref(python內置)、werkzeug.serving、twisted.web等,具體可見Servers which support WSGI。

當前運行在WSGI之上的web框架有Bottle、Flask、Django等,具體可見Frameworks that run on WSGI。

WSGI server所做的工作僅僅是將從客戶端收到的請求傳遞給WSGI application,然后將WSGI application的返回值作為響應傳給客戶端。WSGI applications 可以是棧式的,這個棧的中間部分叫做中間件,兩端是必須要實現的application和server。

WSGI教程

這部分內容主要來自WSGI Tutorial。

WSGI application接口

WSGI application接口應該實現為一個可調用對象,例如函數、方法、類、含__call__方法的實例。這個可調用對象可以接收2個參數:

  • 一個字典,該字典可以包含了客戶端請求的信息以及其他信息,可以認為是請求上下文,一般叫做environment(編碼中多簡寫為environ、env);

  • 一個用于發送HTTP響應狀態(HTTP status )、響應頭(HTTP headers)的回調函數。

同時,可調用對象的返回值是響應正文(response body),響應正文是可迭代的、并包含了多個字符串。

WSGI application結構如下:

def application (environ, start_response):

 response_body = 'Request method: %s' % environ['REQUEST_METHOD']

 # HTTP響應狀態
 status = '200 OK'

 # HTTP響應頭,注意格式
 response_headers = [
  ('Content-Type', 'text/plain'),
  ('Content-Length', str(len(response_body)))
 ]

 # 將響應狀態和響應頭交給WSGI server
 start_response(status, response_headers)

 # 返回響應正文
 return [response_body]

Environment

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

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 

# 導入python內置的WSGI server
from wsgiref.simple_server import make_server

def 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設置為text/plain,所以`\n`在瀏覽器中會起到換行的作用

 status = '200 OK'
 response_headers = [
  ('Content-Type', 'text/plain'),
  ('Content-Length', str(len(response_body)))
 ]
 start_response(status, response_headers)

 return [response_body]

# 實例化WSGI server
httpd = make_server (
 '127.0.0.1', 
 8051, # port
 application # WSGI application,此處就是一個函數
)

# handle_request函數只能處理一次請求,之后就在控制臺`print 'end'`了
httpd.handle_request()

print 'end'

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

另外,瀏覽器請求一次后,environment.py就結束了,程序在終端中輸出內容如下:

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

可迭代的響應

如果把上面的可調用對象application的返回值:

return [response_body]

改成:

return response_body

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

如果可迭代響應含有多個字符串,那么Content-Length應該是這些字符串長度之和:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 

from wsgiref.simple_server import make_server

def 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_body

httpd = make_server('localhost', 8051, application)
httpd.handle_request()

print 'end'

解析GET請求

運行environment.py,在瀏覽器中訪問http://localhost:8051/?age=10&hobbies=software&hobbies=tunning,可以在響應的內容中找到:

QUERY_STRING: age=10&hobbies=software&hobbies=tunning
REQUEST_METHOD: GET

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

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 
from cgi import parse_qs, escape

QUERY_STRING = 'age=10&hobbies=software&hobbies=tunning'
d = parse_qs(QUERY_STRING)
print d.get('age', [''])[0] # ['']是默認值,如果在QUERY_STRING中沒找到age則返回默認值
print d.get('hobbies', [])
print d.get('name', ['unknown'])

print 10 * '*'
print escape('<script>alert(123);</script>')

輸出如下:

10
['software', 'tunning']
['unknown']
**********
&lt;script&gt;alert(123);&lt;/script&gt;

然后,我們可以寫一個基本的處理GET請求的動態網頁了:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 

from wsgiref.simple_server import make_server
from cgi import parse_qs, escape

# html中form的method是get,action是當前頁面
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對應的值
 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)

# 能夠一直處理請求
httpd.serve_forever()

print 'end'

啟動程序,在瀏覽器中訪問http://localhost:8051/、http://localhost:8051/?age=10&hobbies=software&hobbies=tunning感受一下~

這個程序會一直運行,可以使用快捷鍵Ctrl-C終止它。

這段代碼涉及兩個我個人之前沒用過的小技巧:

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

解析POST請求

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

下面是一個可以處理POST請求的動態網站:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 

from wsgiref.simple_server import make_server
from cgi import parse_qs, escape

# html中form的method是post
html = """
<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 可能為空,或者沒有
 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)

 # 獲取數據
 age = d.get('age', [''])[0] 
 hobbies = d.get('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'

 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入門

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

Web server

WSGI server就是一個web server,其處理一個HTTP請求的邏輯如下:

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

app即WSGI application,environ即上文中的environment。可調用對象app返回一個可迭代的值,WSGI server獲得這個值后將數據發送給客戶端。

Web framework/app

即WSGI application。

中間件(Middleware)

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

一個示例

該示例中使用了中間件。

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 

from wsgiref.simple_server import make_server

def 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'

然后

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

在Learn about WSGI還有更多關于WSGI的內容。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“Python中WSGI有什么用”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

盱眙县| 瑞金市| 弥渡县| 当涂县| 故城县| 蕲春县| 红安县| 内黄县| 富阳市| 阜阳市| 琼海市| 福贡县| 昌宁县| 德清县| 德惠市| 扬州市| 盘锦市| 大丰市| 嘉定区| 文安县| 平果县| 密云县| 突泉县| 闽清县| 嵊州市| 宁海县| 郎溪县| 巴林右旗| 城步| 漠河县| 东丽区| 昌都县| 马山县| 尚志市| 府谷县| 天全县| 肇州县| 宣汉县| 庐江县| 保山市| 同江市|