Python自定义HTTP服务器:子类初始化参数跨链路透传问题
问题根因
socketserver 框架的请求处理实例化逻辑是固定的:服务器收到请求后,会自动实例化注册的RequestHandlerClass,实例化时仅固定传入三个参数:请求字节对象、客户端地址元组、当前服务器实例。仅修改Handler类的构造函数增加参数,会因为服务器内部调用构造时不传入额外参数直接抛出参数不匹配错误。
最小改动实现方案
不需要修改RequestHandler的构造函数签名,直接利用框架原生提供的Handler实例持有对应Server实例引用的特性,通过服务器实例完成协议对象的透传,完全兼容原生初始化链路:
- 扩展自定义
ThreadingSimpleServer的初始化方法,增加protocol入参,将传入的协议实例存为服务器实例属性 - 在
MyServer.start()初始化服务器时,将自身持有的self.protocol作为参数传入ThreadingSimpleServer - 请求处理逻辑中,通过
self.server访问绑定了协议实例的服务器对象,即可直接调用协议实例的处理方法
修改后可直接运行的代码
import socketserver from http.server import BaseHTTPRequestHandler, HTTPServer import threading class Protocol(): def processGetReq(self): pass class MyServer(): def __init__(self, protocol: Protocol, srvr_ip="127.0.0.1", srvr_port=10001): self.srvr_addr = (srvr_ip, srvr_port) self.protocol = protocol def start(self): # 初始化服务器时传入持有的协议实例 self.server = self.ThreadingSimpleServer( self.srvr_addr, RequestHandlerClass=self.HttpServer, protocol=self.protocol ) self._server_thread = threading.Thread(target=self._handle_requests) self._server_thread.start() def _handle_requests(self): while 1: self.server.handle_request() def serveForever(self): self._server_thread.join() class HttpServer(BaseHTTPRequestHandler): def _set_headers(self): self.send_response(200) self.send_header('Content-Type', 'text/plain') self.end_headers() def do_GET(self): # 通过self.server访问绑定的协议实例 self.server.protocol.processGetReq() self._set_headers() self.wfile.write(b"OK, get") class ThreadingSimpleServer(socketserver.ThreadingMixIn, HTTPServer): # 扩展初始化方法,接收protocol参数 def __init__(self, server_address, RequestHandlerClass, protocol, bind_and_activate=True): super().__init__(server_address, RequestHandlerClass, bind_and_activate) self.protocol = protocol ################################################################## ##################### START ###################### ################################################################## # 示例自定义Protocol子类 class SomeProtocol(Protocol): def processGetReq(self): print("收到GET请求,执行自定义协议处理逻辑") server = MyServer(SomeProtocol()) server.start() print("Server ready!") server.serveForever()
补充说明
如果需要给RequestHandler传递更多自定义参数,都可以通过扩展ThreadingSimpleServer初始化方法、将参数存为服务器实例属性的方式实现,不需要改动框架原生的Handler实例化逻辑,没有多线程场景下的参数覆盖风险。
内容的提问来源于stack exchange,提问作者Daniel Šebík
相关产品推荐
相关产品推荐

