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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python Web开发:开发wsgi中间件

發布時間:2023/12/10 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python Web开发:开发wsgi中间件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文參考了:

  • github.com/alanctkc/ws…
  • Youtube : Creating WSGI Middleware

上篇文章簡要提到:wsgi 規范中的 app 是一個可調用對象,可以通過嵌套調用的方式實現中間件的功能。這篇文章就來親自動手實現一下。

此文的重點在于 app 端,所以 wsgi 服務器將使用python 內置module wsgiref.simple_server 中的make_server。

創建 app

新建文件 app.py :

def application(environ, start_response):"""The web application."""response_body = ""for key, value in environ.items():response_body += "<p>{} : {}\n</p>".format(key, value)# Set up the response status and headersstatus = '200 OK'response_headers = [('Content-Type', 'text/html; charset=utf-8'),('Content-Length', str(len(response_body))),]start_response(status, response_headers)return [response_body.encode('utf-8')]復制代碼

注意:python3中要求 response_body是 bytes,所以需要 encode()一下。在 python2中是 str,不需要 encode()。

這個 app 做的事情非常簡單,把傳過來的 environ 原樣返回。在開始返回body 之前,調用server傳過來的start_response函數。

簡要說明一下為什么是 retuen [response_body]而不是 return response_body或者 return response_body.split("\n")或者return response_body.split("")?

  • 首先 wsgi 規范說明了app返回的是一個可迭代對象,列表是可迭代的。
  • 其次,對于大多數 app 來說,response_body都不會太長,服務器的內存完成足以一次性裝下,所以最高效的方法就是一次性把response_body全傳過去。

創建 server

新建文件server.py

from wsgiref.simple_server import make_server from app import applicationprint("Server is running at http://localhost:8888 . Press Ctrl+C to stop.") server = make_server('localhost', 8888, application) server.serve_forever()復制代碼

用瀏覽器打開 http://localhost:8888,就可以看到 environ 的詳細內容。其中比較重要的我用紅框框圈了起來。

第一個中間件:cors

簡要了解一下 cors 的機制(詳細的要比這個復雜點):

如果一個ajax請求(XMLHttpRequest)是跨域的,比如說在 http://localhost:9000頁面上向運行在http://localhost:8888的服務器發起請求,瀏覽器就會往請求頭上面加上一個ORIGIN字段,這個字段的值就是localhost:9000。(對應在app 的 environ 參數中,就是 HTTP_ORIGIN)

同時,瀏覽器會先發出OPTIONS請求,服務器要實現這樣的功能:如果想要接收這個請求的話,需要在response 的 headers里面添加一個Access-Control-Allow-Origin字段,值就是請求傳過來的那個ORIGIN。

瀏覽器發出OPTIONS請求并發現返回數據的 headers 里面有Access-Control-Allow-Origin,才會進行下一步發出真正的請求:GET,POST,WAHTERVER。

所以,CORS 是瀏覽器和 Server共同協作來完成的。

看一下代碼:

class CORSMiddleware(object):def __init__(self, app, whitelist=None):"""Initialize the middleware for the specified app."""if whitelist is None:whitelist = []self.app = appself.whitelist = whitelistdef validate_origin(self, origin):"""Validate that the origin of the request is whitelisted."""return origin and origin in self.whitelistdef cors_response_factory(self, origin, start_response):"""Create a start_response method that includes a CORS header for thespecified origin."""def cors_allowed_response(status, response_headers, exc_info=None):"""This wraps the start_response behavior to add some headers."""response_headers.extend([('Access-Control-Allow-Origin', origin)])return start_response(status, response_headers, exc_info)return cors_allowed_responsedef cors_options_app(self, origin, environ, start_response):"""A small wsgi app that responds to preflight requests for thespecified origin."""response_body = 'ok'status = '200 OK'response_headers = [('Content-Type', 'text/plain'),('Content-Length', str(len(response_body))),('Access-Control-Allow-Origin', origin),('Access-Control-Allow-Headers', 'Content-Type'),]start_response(status, response_headers)return [response_body.encode('utf-8')]def cors_reject_app(self, origin, environ, start_response):response_body = 'rejected'status = '200 OK'response_headers = [('Content-Type', 'text/plain'),('Content-Length', str(len(response_body))),]start_response(status, response_headers)return [response_body.encode('utf-8')]def __call__(self, environ, start_response):"""Handle an individual request."""origin = environ.get('HTTP_ORIGIN')if origin:if self.validate_origin(origin):method = environ.get('REQUEST_METHOD')if method == 'OPTIONS':return self.cors_options_app(origin, environ, start_response)return self.app(environ, self.cors_response_factory(origin, start_response))else:return self.cors_reject_app(origin, environ, start_response)else:return self.app(environ, start_response)復制代碼

__init__方法傳入的參數有:下一層的 app(回顧一下前面說的 app 是一層一層的,所以能夠實現中間件)和 client 白名單,只允許來自這個白名單內的ajax 請求。

__call__方法說明這是一個可調用對象(類也可以是可調用的),一樣接收兩個參數:environ和start_response。首先判斷一下 environ 中有沒有HTTP_ORIGIN,有的話就表明屬于跨域請求。如果是跨域,判斷一下 origin 在不咋白名單。如果在白名單里面,如果是 OPTIONS請求,返回cors_options_app里面的對應內容(加上了Access-Control-Allow-Origin header);如果不是OPTIONS請求,調用下一層的 app。如果不在白名單,返回的是cors_reject_app。

修改一下server.py:

app = CORSMiddleware(app=application,whitelist=['http://localhost:9000','http://localhost:9001'] ) server = make_server('localhost', 8000, app) 復制代碼

測試 cors app

這里在運行三個客戶端,[代碼在此]。(github.com/liaochangji…)

運行python client.py:

在瀏覽器打開http://localhost:9000、http://localhost:9001和http://localhost:9002,可以發現http://localhost:9000和http://localhost:9001成功發出了請求,而http://localhost:9002失敗了。

第二個中間件:請求耗時

這個比上一個要簡單很多,相信現在你已經完全能夠理解了:

import timeclass ResponseTimingMiddleware(object):"""A wrapper around an app to print out the response time for eachrequest."""def __init__(self, app):self.app = appdef __call__(self, environ, start_response):"""Meaure the time spent in the application."""start_time = time.time()response = self.app(environ, start_response)response_time = (time.time() - start_time) * 1000timing_text = "總共耗時: {:.10f}ms \n".format(response_time)response = [timing_text.encode('utf-8') + response[0]]return response 復制代碼

再修改一下server.py:

app = ResponseTimingMiddleware(CORSMiddleware(app=application,whitelist=['http://localhost:9000','http://localhost:9001']) ) 復制代碼

再次訪問http://localhost:8000,會看到最前面打印出了此次請求的耗時:

總結一下

我手畫了一個請求圖,希望對你有所幫助:

本文的所有源代碼開源在 github 上:github.com/liaochangji…

希望能點個 star ~

如果你像我一樣真正熱愛計算機科學,喜歡研究底層邏輯,歡迎關注我的微信公眾號:

總結

以上是生活随笔為你收集整理的Python Web开发:开发wsgi中间件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。