如何屏蔽gevent Flask/WSGI HTTP服务器接HTTPS请求的无效HTTP方法错误日志
问题描述
当用户误将HTTPS请求发送到基于gevent运行的纯HTTP Flask服务器时,会生成一条无法通过常规Python异常捕获消除的乱码日志,推测该异常未进入Python代码执行层面。
代码示例
from flask import Flask from gevent.pywsgi import WSGIServer app = Flask(__name__) @app.route("/") def hello_world(): return "Hello, World!" if __name__ == "__main__": http_server = WSGIServer(("0.0.0.0", 8000), app) http_server.serve_forever()
触发命令
curl https://localhost:8000
需消除的日志输出
<gevent._socket3.socket at 0x10272dbe0 object, fd=9, family=2, type=1, proto=0>: (from ('127.0.0.1', 63996)) Invalid HTTP method: "\x16\x03\x01\x01:\x01\x00\x016\x03\x035o;OÀ|¶\x9aã[3F\x81>?ÞB1f'ø×ÈùG\x0eAV\x9c\x1cÿ\x9f I+Hýò¶\x9aݽL\r{p\n" {p" 400 - 0.0005314-05-17 08:09:57] ":65o;OÀ|¶ã[3F>?ÞB1f'ø×ÈùGAVÿò¶Ý½L
解决方案
方法一:消除目标日志
gevent的WSGIServer通过内置的WSGIHandler处理请求日志,我们可以自定义handler并重写log_error方法,过滤掉HTTPS请求导致的无效方法日志:
from flask import Flask from gevent.pywsgi import WSGIServer, WSGIHandler class CustomWSGIHandler(WSGIHandler): def log_error(self, format, *args): # 过滤HTTPS握手数据导致的无效HTTP方法日志 if format == "%s: (from %s) Invalid HTTP method: %r" and len(args) == 3: method = args[2] # HTTPS握手数据以\x16开头(SSL/TLS握手记录标识) if method.startswith('\x16'): return # 其他正常日志保持原有输出逻辑 super().log_error(format, *args) app = Flask(__name__) @app.route("/") def hello_world(): return "Hello, World!" if __name__ == "__main__": http_server = WSGIServer(("0.0.0.0", 8000), app, handler_class=CustomWSGIHandler) http_server.serve_forever()
方法二:添加上下文说明日志
若需要保留提示性日志而非完全消除,可在自定义handler中替换原有乱码日志为友好的上下文提示:
from flask import Flask from gevent.pywsgi import WSGIServer, WSGIHandler import logging # 配置基础日志格式 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class CustomWSGIHandler(WSGIHandler): def log_error(self, format, *args): if format == "%s: (from %s) Invalid HTTP method: %r" and len(args) == 3: method = args[2] client_addr = args[1] if method.startswith('\x16'): # 输出带上下文的友好提示日志 logger.warning(f"收到来自{client_addr}的HTTPS请求,但当前服务器仅支持HTTP协议,请检查请求配置") return super().log_error(format, *args) app = Flask(__name__) @app.route("/") def hello_world(): return "Hello, World!" if __name__ == "__main__": http_server = WSGIServer(("0.0.0.0", 8000), app, handler_class=CustomWSGIHandler) http_server.serve_forever()
内容的提问来源于stack exchange,提问作者Cyberwiz
相关产品推荐
相关产品推荐

