socketserver和WSGI服務端實現教程

Python socketserver 和 WSGI 服務端實現教程

在本文中,我們將詳細解析一個使用 socketserver 模塊實現的簡單 WSGI 服務器。該服務器能夠處理 HTTP 請求,支持 WSGI 應用,并正確處理響應頭和錯誤。

代碼概述

這段代碼定義了一個 run_wsgi 方法,用于處理 HTTP 請求并運行 WSGI 應用。它實現了以下功能:

  1. 處理 Expect: 100-continue 請求頭。
  2. 創建 WSGI 環境字典。
  3. 定義 writestart_response 函數來處理 WSGI 響應。
  4. 執行 WSGI 應用,并將響應發送回客戶端。
  5. 處理連接錯誤和超時。
  6. 在發生異常時記錄錯誤,并返回 InternalServerError 響應。
代碼詳細解析
def run_wsgi(self):# 處理 'Expect: 100-continue' 請求頭if self.headers.get("Expect", "").lower().strip() == "100-continue":self.wfile.write(b"HTTP/1.1 100 Continue\r\n\r\n")# 創建 WSGI 環境字典self.environ = environ = self.make_environ()headers_set = []headers_sent = []# 定義 write 函數,用于發送響應數據def write(data):assert headers_set, "write() before start_response"if not headers_sent:status, response_headers = headers_sent[:] = headers_settry:code, msg = status.split(None, 1)except ValueError:code, msg = status, ""code = int(code)self.send_response(code, msg)header_keys = set()for key, value in response_headers:self.send_header(key, value)key = key.lower()header_keys.add(key)if not ("content-length" in header_keysor environ["REQUEST_METHOD"] == "HEAD"or code < 200or code in (204, 304)):self.close_connection = Trueself.send_header("Connection", "close")if "server" not in header_keys:self.send_header("Server", self.version_string())if "date" not in header_keys:self.send_header("Date", self.date_time_string())self.end_headers()assert isinstance(data, bytes), "applications must write bytes"self.wfile.write(data)self.wfile.flush()# 定義 start_response 函數,用于設置響應頭def start_response(status, response_headers, exc_info=None):if exc_info:try:if headers_sent:reraise(*exc_info)finally:exc_info = Noneelif headers_set:raise AssertionError("Headers already set")headers_set[:] = [status, response_headers]return write# 執行 WSGI 應用def execute(app):application_iter = app(environ, start_response)try:for data in application_iter:write(data)if not headers_sent:write(b"")finally:if hasattr(application_iter, "close"):application_iter.close()application_iter = Nonetry:execute(self.server.app)except (_ConnectionError, socket.timeout) as e:self.connection_dropped(e, environ)except Exception:if self.server.passthrough_errors:raisefrom .debug.tbtools import get_current_tracebacktraceback = get_current_traceback(ignore_system_exceptions=True)try:if not headers_sent:del headers_set[:]execute(InternalServerError())except Exception:passself.server.log("error", "Error on request:\n%s", traceback.plaintext)

分步驟講解

  1. 處理 Expect: 100-continue 請求頭
if self.headers.get("Expect", "").lower().strip() == "100-continue":self.wfile.write(b"HTTP/1.1 100 Continue\r\n\r\n")

當客戶端發送帶有 Expect: 100-continue 請求頭的請求時,服務器應先響應 100 Continue,然后再繼續處理請求。這段代碼處理了這一邏輯。

  1. 創建 WSGI 環境字典
self.environ = environ = self.make_environ()

這行代碼調用 make_environ 方法,創建一個 WSGI 環境字典 environ,包含了請求的所有必要信息,如請求方法、路徑、頭信息等。

  1. 定義 write 函數
def write(data):assert headers_set, "write() before start_response"if not headers_sent:status, response_headers = headers_sent[:] = headers_settry:code, msg = status.split(None, 1)except ValueError:code, msg = status, ""code = int(code)self.send_response(code, msg)header_keys = set()for key, value in response_headers:self.send_header(key, value)key = key.lower()header_keys.add(key)if not ("content-length" in header_keysor environ["REQUEST_METHOD"] == "HEAD"or code < 200or code in (204, 304)):self.close_connection = Trueself.send_header("Connection", "close")if "server" not in header_keys:self.send_header("Server", self.version_string())if "date" not in header_keys:self.send_header("Date", self.date_time_string())self.end_headers()assert isinstance(data, bytes), "applications must write bytes"self.wfile.write(data)self.wfile.flush()

write 函數負責發送響應數據。在首次調用時,它還會發送響應頭。它確保在 start_response 被調用后才允許發送數據,并確保數據是字節類型。

  1. 定義 start_response 函數
def start_response(status, response_headers, exc_info=None):if exc_info:try:if headers_sent:reraise(*exc_info)finally:exc_info = Noneelif headers_set:raise AssertionError("Headers already set")headers_set[:] = [status, response_headers]return write

start_response 函數用于設置響應頭。它會在 WSGI 應用中被調用,接受狀態碼和響應頭列表。如果發生異常且響應頭已經發送,它會重新引發異常。

  1. 執行 WSGI 應用
def execute(app):application_iter = app(environ, start_response)try:for data in application_iter:write(data)if not headers_sent:write(b"")finally:if hasattr(application_iter, "close"):application_iter.close()application_iter = None

execute 函數執行 WSGI 應用,并迭代應用的輸出。它調用 write 函數發送響應數據,并在最后關閉應用迭代器。

  1. 錯誤處理
try:execute(self.server.app)
except (_ConnectionError, socket.timeout) as e:self.connection_dropped(e, environ)
except Exception:if self.server.passthrough_errors:raisefrom .debug.tbtools import get_current_tracebacktraceback = get_current_traceback(ignore_system_exceptions=True)try:if not headers_sent:del headers_set[:]execute(InternalServerError())except Exception:passself.server.log("error", "Error on request:\n%s", traceback.plaintext)

這部分代碼處理各種異常。如果發生連接錯誤或超時,會調用 connection_dropped 方法處理。如果發生其他異常且 passthrough_errors 未啟用,會記錄錯誤并返回 InternalServerError 響應。

總結

通過使用 socketserver 模塊和 WSGI 規范,可以實現一個簡單但功能強大的網絡服務器。本文中的代碼展示了如何處理請求頭、創建 WSGI 環境、發送響應數據、處理錯誤等。希望通過這篇教程,你能夠更好地理解和使用 socketserver 模塊來開發自己的網絡服務器應用。更多詳細信息和示例請參考官方文檔。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/43249.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/43249.shtml
英文地址,請注明出處:http://en.pswp.cn/web/43249.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【深入理解JVM】關于Object o = new Object()

1. 解釋一下對象的創建過程 “半初始化”狀態通常指的是對象在內存分配后、但在完全初始化之前的一種狀態。在Java中&#xff0c;雖然JVM的規范和設計努力避免對象處于這種不穩定的狀態&#xff0c;但在多線程環境下&#xff0c;由于指令重排序等并發問題&#xff0c;仍有可能…

Apache Spark詳解

目錄 性能優化 銀行業務案例&#xff1a; 步驟1&#xff1a;環境準備和數據加載 步驟2&#xff1a;數據探索和預處理 步驟3&#xff1a;特征工程 步驟4&#xff1a;數據轉換 步驟5&#xff1a;構建機器學習模型 步驟6&#xff1a;模型評估 步驟7&#xff1a;部署和監控…

Spring JdbcTemplate使用

maven引入Spring JDBC <dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.19</version></dependency> Spring配置中配置 <!-- DataSource配置 --><bean id"…

java代理簡單理解

一、什么是代理 舉例說明&#xff1a;當我想買一臺電腦&#xff0c;國內太貴了。委托好友A在國外幫忙買。 這個情節中我要實現的動作和好友實現的動作一樣&#xff0c;都是買電腦。好友幫我完成了這個動作&#xff0c;這就是代理。 類A和類B都實現一個interface接口C&#x…

【LeetCode刷題筆記】LeetCode.24.兩兩交換鏈表中的節點

創作不易&#xff0c;本篇文章如果幫助到了你&#xff0c;還請點贊 關注支持一下?>&#x16966;<)!! 主頁專欄有更多知識&#xff0c;如有疑問歡迎大家指正討論&#xff0c;共同進步&#xff01; 更多算法知識專欄&#xff1a;算法分析&#x1f525; 給大家跳段街舞感謝…

新手小白的pytorch學習第一彈-------張量

1 導入pytorch包 import torch2 創建張量&#xff08;tensor&#xff09; scalar標量 scalar torch.tensor(7) scalartensor(7)scalar.ndim查看scalar的維度&#xff0c;因為scalar是標量&#xff0c;所以維度為0 0scalar.shapetorch.Size([])torch.item()7vector&#xf…

Apache功能配置:訪問控制、日志分割; 部署AWStats日志分析工具

目錄 保持連接 訪問控制 只允許指定ip訪問 拒絕指定主機其他正常訪問 用戶授權 日志格式 日志分割 操作步驟 使用第三方工具cronolog分割日志 AWStats日志分析 操作步驟 訪問AwStats分析系統 保持連接 Apache通過設置配置文件httpd-default.conf中相關的連接保持參…

基于Java的科大訊飛大模型API調用實現

寫在前面&#xff1a;因為現在自己實習的公司新拓展的一個業務是結合AI的低代碼平臺&#xff0c;我負責后端的開發&#xff0c;之前一直都是直接使用gpt或者文心一言等ui界面來直接使用大模型&#xff0c;從來沒有自己調接口過&#xff0c;所以本文記錄一下自己第一次使用大模型…

源代碼防泄漏的正確方法

為了保護公司的源代碼不被泄露&#xff0c;IT企業可以采取一系列嚴格的安全措施。這些措施涵蓋技術手段、管理策略和操作流程&#xff0c;形成多層次的防護體系做到源代碼防泄漏工作。 技術手段 1、源代碼加密&#xff1a; 采用高級加密標準&#xff08;AES&#xff09;或其他…

【QT】QComboBox允許輸入查詢,且不區分大小寫

目錄 0.簡介 1.環境 2.詳細代碼 3.參考 0.簡介 項目需求&#xff0c;原本有一個下拉框&#xff0c;但是條目太多&#xff0c;不好搜索&#xff0c;所以用戶要求可以輸入查找 修改前 &#xff1a; 修改后&#xff1a; 1.環境 windows11 vs-code qt5.12 2.詳細代碼 QComboB…

中小企業和數智化的距離,只差一塊華為IdeaHub

每次談及中小企業數智化的話題&#xff0c;被提到最多的總是“三不”難題&#xff0c;即不想轉、不敢轉、不會轉。 為了破解這一困局&#xff0c;政府多次在工作報告中提到“深入開展中小企業數字化賦能專項行動”&#xff0c;并在各地為中小企業創新提供政策支持。此外&#…

Android --- Kotlin學習之路:基礎語法學習筆記

------>可讀可寫變量 var name: String "Hello World";------>只讀變量 val name: String "Hello World"------>類型推斷 val name: String "Hello World" 可以寫成 val name "Hello World"------>基本數據類型 1…

MD5加密和注冊頁面的編寫

MD5加密 1.導入包 npm install --save ts-md5 2.使用方式 import { Md5 } from ts-md5; //md5加密后的密碼 const md5PwdMd5.hashStr("123456").toUpperCase(); 遇見的問題及用到的技術 注冊頁面 register.vue代碼 <template><div class"wappe…

從零開始學習嵌入式----Linux 命令行,常用命令速記指南

目錄 一、文件操作 二、文本操作 三、系統管理 四、網絡操作 五、其他常用命令 六、學習建議 在 Linux 世界里&#xff0c;命令行就像一把瑞士軍刀&#xff0c;掌握了它&#xff0c;你就能游刃有余地操控整個系統。但面對茫茫多的命令&#xff0c;新手往往會感到無所適從…

關于Python中的字典你所不知道的七個技巧

01 引言 Python是我最喜歡的編程語言之一&#xff0c;它向來以其簡單性、多功能性和可讀性而聞名。 字典作為Python中最常使用的數據類型&#xff0c;大家幾乎每個人都或多或少在項目中使用過字典&#xff0c;但是字典里有一些潛在的技巧可能并不是每個同學都會用到。 在本文…

相同含義但不同類型字段作為join條件時注意事項

假設表A和表B中都有表示學號的stu_id字段&#xff0c;但該字段在表A和表B中類型分別為bigint和string。當直接通過該字段進行join時&#xff0c;一般情況下可以得到我們預期的結果。 select a.stu_id from a as r join b as l on r.stu_id l.stu_id 但是如果學號長度較長的…

【UE5.1 角色練習】16-槍械射擊——瞄準

目錄 效果 步驟 一、瞄準時拉近攝像機位置 二、瞄準偏移 三、向指定方向射擊 四、連發 效果 步驟 一、瞄準時拉近攝像機位置 打開角色藍圖&#xff0c;在事件圖表中添加如下節點&#xff0c;當進入射擊狀態時設置目標臂長度為300&#xff0c;從而拉近視角。 但是這樣切…

勇攀新高峰|暴雨信息召開2024年中述職工作會議

7月8日至9日&#xff0c;暴雨信息召開2024年中述職工作會議&#xff0c;總結回顧了上半年的成績和不足&#xff0c;本次會議采用線上線下的方式舉行&#xff0c;公司各部門管理人員、前臺市場營銷人員參加述職&#xff0c;公司領導班子出席會議。 本次述職采取了現場匯報點評的…

關于宏v4l2_subdev_call的拆解

struct v4l2_subdev *sd結構體 struct v4l2_subdev { #if defined(CONFIG_MEDIA_CONTROLLER)struct media_entity entity; #endifstruct list_head list;struct module *owner;bool owner_v4l2_dev;u32 flags;struct v4l2_device *v4l2_dev;const struct v4l2_subdev_ops *op…

數字滾動動畫~

前言 數字從0.00滾動到某個數值的動畫 實現&#xff08;React版本&#xff09; Dom <div className"number" ref{numberRef}>0.00</div> JS const _initNumber () > {const targetNumber 15454547.69;const duration 1500;const numberElement…