python基礎教程,python入門基礎教程-Python入門基礎教程:WSGI

 2023-11-18 阅读 29 评论 0

摘要:原標題:Python入門基礎教程:WSGI python基礎教程?WSGI 簡介 WSGI 是什么 python爬蟲教程?WSGI 是 Python Web Server Gateway Interface 的縮寫,是描述 Web 服務器與 Python 應用程序之間如何交互的接口規范。該規范具體描述在 PEP-3333。 這個規范相當

原標題:Python入門基礎教程:WSGI

python基礎教程?WSGI 簡介

WSGI 是什么

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

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

python自學入門。WSGI 應用程序

符合 WSGI 規范的 Python 應用程序必須是:

一個可調用對象(callable object,例如函數、類、實現了 __call__ 方法的實例)

接受兩個由 WSGI Server 提供的參數:

environ 字典,包含 環境變量,請求數據,如 REQUEST_METHOD,PATH_INFO,QUERY_STRING 等

start_response 函數,開始響應請求的回調函數,用于發送響應狀態(HTTP status) 和響應頭(HTTP headers)

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

下面分別以函數、類、實現了 __call__ 方法的實例來演示符合 WSGI 規范的 Python 應用程序:

# 可調用對象是一個函數

def simple_app(environ, start_response):

# 響應狀態(狀態碼和狀態信息)

status = '200 OK'

# 響應體

response_body = b"Hello WSGI"

# 響應頭,是一個列表,每對鍵值都必須是一個 tuple

response_headers = [('Content-type', 'text/plain'),

('Content-Length', str(len(response_body)))]

# 回調 WSGI 服務器提供的 start_response,返回響應狀態和響應頭

start_response(status, response_headers)

# 返回響應體,由 bytes 類型元素組成的可迭代對象

return [response_body]

?

# 可調用對象是一個類

class AppClass:

"""可調用對象是 AppClass 類,調用方法:

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

?

?

# 可調用對象是一個類實例

class AnotherAppClass:

"""可調用對象是 AnotherAppClass 類實例,調用方法:

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 應用程序對應的 WSGI 服務器需要完成以下工作:

接收 HTTP 請求,返回 HTTP 響應

提供 environ 數據,實現回調函數 start_response

調用 WSGI application,并將 environ,start_response 作為參數傳入

簡化版 WSGI 服務器內部的實現流程:

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 應用程序,一個可調用對象

def run_with_cgi(application):

# 準備 environ 參數數據

# 內部包含本次 HTTP 請求的數據,如 REQUEST_METHOD, PATH_INFO, QUERY_STRING 等

environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()}

# WSGI 環境變量

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 Asserti("write() before start_response()")

elif not headers_sent:

# 在第一次發送響應體之前,發送已經存在的響應頭

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 回調函數,根據 WSGI 應用程序傳遞過來的 HTTP status 和 response_headers

# 設置響應狀態和響應頭

def start_response(status, response_headers, exc_info=None):

# 處理異常情況

if exc_info:

pass

?

headers_set[:] = [status, response_headers]

?

return write

?

# 調用 WSGI 應用程序,傳入準備好的 environ(請求數據)和 start_response(開始響應回調函數)

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 調用,返回 WSGI 應用程序

調用 WSGI 應用程序,傳入 environ 和 start_response

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

from wsgiref.simple_server import make_server

?

def app(environ, start_response):

# 響應狀態(狀態碼和狀態信息)

status = '200 OK'

# 響應體

response_body = b"Hello WSGI"

# 響應頭,是一個列表,每對鍵值都必須是一個 tuple

response_headers = [('Content-type', 'text/plain'),

('Content-Length', str(len(response_body)))]

# 回調 WSGI 服務器提供的 start_response,返回響應狀態和響應頭

start_response(status, response_headers)

# 返回響應體,由 bytes 類型元素組成的可迭代對象

return [response_body]

?

?

# 針對請求數據進行處理的中間件

class WhitelistMiddleware(object):

def __init__(self, app):

self.app = app

?

# 類實例被調用時,根據從請求中獲得的 HTTP_HOST 實現白名單功能

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)

?

?

# 針對響應數據進行處理的中間件

class UpperMiddleware(object):

def __init__(self, app):

self.app = app

?

# 類實例被調用時,將響應體的內容轉換成大寫格式

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()

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

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

from wsgiref.simple_server import make_server

?

# 請求 path 分發中間件

class RouterMiddleware(object):

def __init__(self):

# 保存 path 與應用程序對應關系的字典

self.path_info = {}

def route(self, environ, start_response):

application = self.path_info[environ['PATH_INFO']]

return application(environ, start_response)

# 類實例被調用時,保存 path 和應用程序對應關系

def __call__(self, path):

def wrapper(application):

self.path_info[path] = application

return wrapper

?

router = RouterMiddleware()

?

?

@router('/hello') # 調用 RouterMiddleware 類實例,保存 path 和應用程序對應關系

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 接口規范描述的 WSGI 應用程序太過于底層,對于開發人員很不友好。人們通常會使用 Web Framework 來完成一個 Web 應用的開發工作,然后會把這個 Web 應用部署在為生產環境準備的 Web 服務器上。

常用的 Python Web Framework:

Django

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

Flask

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

Tornado

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

Bottle

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

常用的 WSGI Web Server:

Gunicorn

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

uWSGI

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

責任編輯:

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/177019.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息