真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

WSGI-Web服務器與Python應用程序如何交互規(guī)范-創(chuàng)新互聯(lián)

今天就跟大家聊聊有關(guān)WSGI -Web 服務器與 Python 應用程序如何交互規(guī)范,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

成都創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務領(lǐng)域包括:成都網(wǎng)站建設、成都網(wǎng)站設計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務,滿足客戶于互聯(lián)網(wǎng)時代的寶雞網(wǎng)站設計、移動媒體設計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡建設合作伙伴!

WSGI -Web 服務器與 Python 應用程序如何交互規(guī)范

WSGI 是什么

WSGI 是 Python Web Server Gateway Interface 的縮寫,是描述 Web 服務器與 Python 應用程序之間如何交互的接口規(guī)范。該規(guī)范具體描述在 PEP-3333。

這個規(guī)范相當于 Web 服務器和 Python 應用程序之間的橋梁。對于 Web 服務器,WSGI 描述了如何把用戶的請求數(shù)據(jù)交給 Python 應用程序;對于 Python 應用程序,WSGI 描述了如何獲得用戶的請求數(shù)據(jù),如何將請求的處理結(jié)果返回給 Web 服務器。

WSGI -Web 服務器與 Python 應用程序如何交互規(guī)范

WSGI 應用程序

符合 WSGI 規(guī)范的 Python 應用程序必須是:

  • 一個可調(diào)用對象(callable object,例如函數(shù)、類、實現(xiàn)了 __call__ 方法的實例)

  • 接受兩個由 WSGI Server 提供的參數(shù):

  • environ 字典,包含 環(huán)境變量,請求數(shù)據(jù),如 REQUEST_METHOD,PATH_INFO,QUERY_STRING 等

  • start_response 函數(shù),開始響應請求的回調(diào)函數(shù),用于發(fā)送響應狀態(tài)(HTTP status) 和響應頭(HTTP headers)

  • 返回一個由 bytes 類型元素組成的可迭代對象(通常是一個字節(jié)序列),即響應正文(Response body)

下面分別以函數(shù)、類、實現(xiàn)了 __call__ 方法的實例來演示符合 WSGI 規(guī)范的 Python 應用程序:

# 可調(diào)用對象是一個函數(shù)
def simple_app(environ, start_response):
 # 響應狀態(tài)(狀態(tài)碼和狀態(tài)信息)
 status = '200 OK'
 # 響應體
 response_body = b"Hello WSGI"
 # 響應頭,是一個列表,每對鍵值都必須是一個 tuple
 response_headers = [('Content-type', 'text/plain'),
 ('Content-Length', str(len(response_body)))]
 
 # 回調(diào) WSGI 服務器提供的 start_response,返回響應狀態(tài)和響應頭
 start_response(status, response_headers)
 
 # 返回響應體,由 bytes 類型元素組成的可迭代對象
 return [response_body]
# 可調(diào)用對象是一個類
class AppClass:
 """可調(diào)用對象是 AppClass 類,調(diào)用方法: 
 for body in AppClass(env, start_response):
 process_body(body)
 """
 def __init__(self, environ, start_response):
 self.environ = environ
 self.start = start_response
 def __iter__(self):
 status = '200 OK'
 response_body = b"Hello WSGI"
 response_headers = [('Content-type', 'text/plain'),
 ('Content-Length', str(len(response_body)))]
 self.start(status, response_headers)
 yield response_body
# 可調(diào)用對象是一個類實例
class AnotherAppClass:
 """可調(diào)用對象是 AnotherAppClass 類實例,調(diào)用方法:
 app = AnotherAppClass()
 for body in app(env, start_response):
 process_body(body)
 """
 def __init__(self):
 pass
 def __call__(self, environ, start_response):
 status = '200 OK'
 response_body = b"Hello WSGI"
 response_headers = [('Content-type', 'text/plain'),
 ('Content-Length', str(len(response_body)))]
 start_response(status, response_headers)
 yield response_body

WSGI 服務器

跟 WSGI 應用程序?qū)?WSGI 服務器需要完成以下工作:

  • 接收 HTTP 請求,返回 HTTP 響應

  • 提供 environ 數(shù)據(jù),實現(xiàn)回調(diào)函數(shù) start_response

  • 調(diào)用 WSGI application,并將 environ,start_response 作為參數(shù)傳入

簡化版 WSGI 服務器內(nèi)部的實現(xiàn)流程:

import os, sys
def unicode_to_wsgi(u):
 return u.decode('utf-8')
def wsgi_to_bytes(s):
 return s.encode('utf-8')
# application 是 WSGI 應用程序,一個可調(diào)用對象
def run_with_cgi(application):
 # 準備 environ 參數(shù)數(shù)據(jù)
 # 內(nèi)部包含本次 HTTP 請求的數(shù)據(jù),如 REQUEST_METHOD, PATH_INFO, QUERY_STRING 等
 environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()}
 # WSGI 環(huán)境變量
 environ['wsgi.input'] = sys.stdin.buffer
 environ['wsgi.errors'] = sys.stderr
 environ['wsgi.version'] = (1, 0)
 environ['wsgi.multithread'] = False
 environ['wsgi.multiprocess'] = True
 environ['wsgi.run_once'] = True
 if environ.get('HTTPS', 'off') in ('on', '1'):
 environ['wsgi.url_scheme'] = 'https'
 else:
 environ['wsgi.url_scheme'] = 'http'
 headers_set = []
 headers_sent = []
 def write(data):
 out = sys.stdout.buffer
 
 if not headers_set:
 raise AssertionError("write() before start_response()")
 elif not headers_sent:
 # 在第一次發(fā)送響應體之前,發(fā)送已經(jīng)存在的響應頭
 status, response_headers = headers_sent[:] = headers_set
 out.write(wsgi_to_bytes('Status: %s
' % status))
 for header in response_headers:
 out.write(wsgi_to_bytes('%s: %s
' % header))
 out.write(wsgi_to_bytes('
'))
 out.write(data)
 out.flush()
 # start_response 回調(diào)函數(shù),根據(jù) WSGI 應用程序傳遞過來的 HTTP status 和 response_headers
 # 設置響應狀態(tài)和響應頭
 def start_response(status, response_headers, exc_info=None):
 # 處理異常情況
 if exc_info:
 pass
 headers_set[:] = [status, response_headers]
 return write
 # 調(diào)用 WSGI 應用程序,傳入準備好的 environ(請求數(shù)據(jù))和 start_response(開始響應回調(diào)函數(shù))
 result = application(environ, start_response)
 
 # 處理響應體
 try:
 for data in result:
 if data:
 write(data)
 finally:
 if hasattr(result, 'close'):
 result.close()

Middleware

Middleware(中間件) 處于 WSGI 服務器和 WSGI 應用程序之間。對于 WSGI 應用程序它相當于 WSGI 服務器,而對于 WSGI 服務器 它相當于 WSGI 應用程序。它很像 WSGI 應用程序,接收到請求之后,做一些針對請求的處理,同時它又能在接收到響應之后,做一些針對響應的處理。所以 Middleware 的特點是:

  • 被 WSGI 服務器或其他 Middleware 調(diào)用,返回 WSGI 應用程序

  • 調(diào)用 WSGI 應用程序,傳入 environ 和 start_response

我們以白名單過濾和響應后續(xù)處理來演示 Middleware:

from wsgiref.simple_server import make_server
def app(environ, start_response):
 # 響應狀態(tài)(狀態(tài)碼和狀態(tài)信息)
 status = '200 OK'
 # 響應體
 response_body = b"Hello WSGI"
 # 響應頭,是一個列表,每對鍵值都必須是一個 tuple
 response_headers = [('Content-type', 'text/plain'),
 ('Content-Length', str(len(response_body)))]
 
 # 回調(diào) WSGI 服務器提供的 start_response,返回響應狀態(tài)和響應頭
 start_response(status, response_headers)
 
 # 返回響應體,由 bytes 類型元素組成的可迭代對象
 return [response_body]
# 針對請求數(shù)據(jù)進行處理的中間件
class WhitelistMiddleware(object):
 def __init__(self, app):
 self.app = app
 # 類實例被調(diào)用時,根據(jù)從請求中獲得的 HTTP_HOST 實現(xiàn)白名單功能
 def __call__(self, environ, start_response):
 ip_addr = environ.get('HTTP_HOST').split(':')[0]
 if ip_addr not in ('127.0.0.1'):
 start_response('403 Forbidden', [('Content-Type', 'text/plain')])
 return [b'Forbidden']
 return self.app(environ, start_response)
# 針對響應數(shù)據(jù)進行處理的中間件
class UpperMiddleware(object):
 def __init__(self, app):
 self.app = app
 # 類實例被調(diào)用時,將響應體的內(nèi)容轉(zhuǎn)換成大寫格式
 def __call__(self, environ, start_response):
 for data in self.app(environ, start_response):
 yield data.upper()
if __name__ == '__main__':
 app = UpperMiddleware(WhitelistMiddleware(app))
 with make_server('', 8000, app) as httpd:
 print("Serving on port 8000...")
 httpd.serve_forever()

上面例子是一份完整可運行的代碼。函數(shù) app 是 WSGI 應用程序,WhitelistMiddleware 和 UpperMiddleware 是 WSGI Middleware,WSGI 服務器使用的是 Python 內(nèi)置的 wsgiref 模塊(wsgiref 模塊是 Python 3 提供的 WSGI 規(guī)范的參考實現(xiàn),wsgiref 中的 WSGI 服務器可用于開發(fā)測試,不能使用在生產(chǎn)環(huán)境)。

在 WSGI 規(guī)范中給出了一些 Middleware 的使用場景,其中根據(jù)請求路徑分發(fā)到不同應用程序的場景,正是一個 Web Framework 最基本的一項功能。下面我們來看一個通過 Middleware 實現(xiàn)的路由轉(zhuǎn)發(fā)例子:

from wsgiref.simple_server import make_server
# 請求 path 分發(fā)中間件
class RouterMiddleware(object):
 def __init__(self):
 # 保存 path 與應用程序?qū)P(guān)系的字典
 self.path_info = {}
 
 def route(self, environ, start_response):
 application = self.path_info[environ['PATH_INFO']]
 return application(environ, start_response)
 
 # 類實例被調(diào)用時,保存 path 和應用程序?qū)P(guān)系
 def __call__(self, path):
 def wrapper(application):
 self.path_info[path] = application
 return wrapper
router = RouterMiddleware()
@router('/hello') # 調(diào)用 RouterMiddleware 類實例,保存 path 和應用程序?qū)P(guān)系
def hello(environ, start_response):
 status = '200 OK'
 response_body = b"Hello"
 response_headers = [('Content-type', 'text/plain'),
 ('Content-Length', str(len(response_body)))]
 start_response(status, response_headers)
 return [response_body]
@router('/world')
def world(environ, start_response):
 status = '200 OK'
 response_body = b'World'
 response_headers = [('Content-type', 'text/plain'),
 ('Content-Length', str(len(response_body)))]
 start_response(status, response_headers)
 return [response_body]
@router('/')
def hello_world(environ, start_response):
 status = '200 OK'
 response_body = b'Hello World'
 response_headers = [('Content-type', 'text/plain'),
 ('Content-Length', str(len(response_body)))]
 start_response(status, response_headers)
 return [response_body]
def app(environ, start_response):
 return router.route(environ, start_response)
if __name__ == '__main__':
 with make_server('', 8000, app) as httpd:
 print("Serving on port 8000...")
 httpd.serve_forever()

WSGI 接口規(guī)范描述的 WSGI 應用程序太過于底層,對于開發(fā)人員很不友好。人們通常會使用 Web Framework 來完成一個 Web 應用的開發(fā)工作,然后會把這個 Web 應用部署在為生產(chǎn)環(huán)境準備的 Web 服務器上。

常用的 Python Web Framework:

  • Django

  • 一個功能完備的 Web 框架,擁有龐大的開發(fā)者社區(qū)和豐富的第三方庫。

  • Flask

  • 一款微型框架,構(gòu)建更小應用、API 和 web 服務。是任何不適用 Django 的 Python web 應用的默認選擇。

  • Tornado

  • 一個異步 web 框架,原生支持 WebSocket。

  • Bottle

  • 更小的 Web 框架,整個框架只有一個 Python 文件,是不錯的源碼學習案例。

常用的 WSGI Web Server:

  • Gunicorn

  • 純 Python 實現(xiàn)的 WSGI 服務器,擁有十分簡單的配置和十分合理的默認配置,使用簡單。

  • uWSGI

  • 基于 uwsgi 協(xié)議的,功能十分強大的 Web 服務器,同時也支持 Python WSGI 協(xié)議。性能很好,但配置復雜。

看完上述內(nèi)容,你們對WSGI -Web 服務器與 Python 應用程序如何交互規(guī)范有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設公司行業(yè)資訊頻道,感謝大家的支持。


當前題目:WSGI-Web服務器與Python應用程序如何交互規(guī)范-創(chuàng)新互聯(lián)
URL地址:http://weahome.cn/article/csheps.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部