基于SimpleHTTPRequestHandler的自定义处理器如何设置协议版本?
问题:自定义HTTP服务器无法正确应用HTTP/1.1协议版本
我基于Python的http.server模块编写了自定义脚本,目标是处理自定义路径“/files”以JSON格式返回文件列表。--protocol参数是Python 3.11为http.server模块新增的,我使用Python 3.11.4,尝试通过以下代码支持该参数:
import json import os import sys from functools import partial from http.server import SimpleHTTPRequestHandler, test from pathlib import Path class HTTPRequestHandler(SimpleHTTPRequestHandler): def do_GET(self) -> None: if self.path == '/files': response = bytes(self._get_response(), 'utf-8') self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(response))) self.end_headers() self.wfile.write(response) return return super().do_GET() def _get_response(self) -> str: results = [] for item in Path(self.directory).rglob('*'): if item.is_file(): if __file__ in str(item): continue file_size = str(os.stat(item).st_size) relative_file_path = os.path.relpath(item, self.directory) if sys.platform == 'win32': relative_file_path = relative_file_path.replace('\\', '/') results.append(dict(file=relative_file_path, size=file_size)) return json.dumps(results) if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument('-b', '--bind', metavar='ADDRESS', help='bind to this address ' '(default: all interfaces)') parser.add_argument('-d', '--directory', default=os.getcwd(), help='serve this directory ' '(default: current directory)') parser.add_argument('-p', '--protocol', metavar='VERSION', default='HTTP/1.1', help='conform to this HTTP version ' '(default: %(default)s)') parser.add_argument('port', default=8000, type=int, nargs='?', help='bind to this port ' '(default: %(default)s)') args = parser.parse_args() handler_class = partial(HTTPRequestHandler, directory=args.directory) test(HandlerClass=handler_class, port=args.port, bind=args.bind, protocol=args.protocol)
执行命令:
python server.py --bind <ip> <port> -p HTTP/1.1
但响应头仍显示“HTTP/1.0”版本,请问哪里操作有误?
解决方案
问题出在http.server.test()函数的protocol参数仅用于配置底层服务器套接字的协议标识,但SimpleHTTPRequestHandler默认使用HTTP/1.0作为响应的协议版本,这个属性不会被test()函数自动覆盖。
要让响应头使用指定的HTTP版本,需要将protocol_version参数传递给自定义的HTTPRequestHandler,具体有两种修改方式:
方式1:通过partial直接传递协议版本
修改handler_class的定义,把args.protocol作为protocol_version参数传入:
handler_class = partial(HTTPRequestHandler, directory=args.directory, protocol_version=args.protocol)
方式2:在Handler类中动态控制协议版本
如果需要更灵活的逻辑,可以在Handler的初始化方法中设置:
class HTTPRequestHandler(SimpleHTTPRequestHandler): def __init__(self, *args, protocol_version=None, **kwargs): super().__init__(*args, **kwargs) if protocol_version: self.protocol_version = protocol_version # 其余方法保持不变
然后同样通过partial传递参数:
handler_class = partial(HTTPRequestHandler, directory=args.directory, protocol_version=args.protocol)
修改后重新执行命令,响应头就会显示正确的HTTP/1.1版本了。
内容的提问来源于stack exchange,提问作者Pavel
相关产品推荐
相关产品推荐

