python实现Web服务器 监听8080端口
工程结构

web_server.py
# web_server.py from http.server import HTTPServer, BaseHTTPRequestHandler from urllib.parse import urlparse, parse_qs import json import threading import time # 注意:这里不直接初始化log_manager,由main.py控制 # 使用一个全局变量来存储logger,在init函数中设置 _web_logger = None def init_web_server(logger_instance): """初始化Web服务器,设置logger实例""" global _web_logger _web_logger = logger_instance class RequestHandler(BaseHTTPRequestHandler): """自定义HTTP请求处理器""" def _get_logger(self): """获取logger实例""" global _web_logger if _web_logger is None: # 如果没有设置logger,创建一个基本的 import logging return logging.getLogger('web_server_fallback') return _web_logger def do_GET(self): """处理GET请求""" logger = self._get_logger() try: # 解析URL和参数 parsed_url = urlparse(self.path) query_params = parse_qs(parsed_url.query) # 记录请求信息 logger.info(f"收到GET请求: {self.path}") logger.debug(f"客户端: {self.client_address}") logger.debug(f"请求头: {dict(self.headers)}") logger.info(f"解析的参数: {query_params}") # 根据路径进行路由 if parsed_url.path == '/': self._handle_home(query_params) elif parsed_url.path == '/api/data': self._handle_api_data(query_params) elif parsed_url.path == '/api/user': self._handle_api_user(query_params) elif parsed_url.path == '/health': self._handle_health_check() else: self._handle_not_found() except Exception as e: logger.error(f"处理请求时出错: {e}", exc_info=True) self._send_error_response(500, f"服务器内部错误: {str(e)}") def do_POST(self): """处理POST请求""" logger = self._get_logger() try: # 获取内容长度 content_length = int(self.headers.get('Content-Length', 0)) # 读取POST数据 post_data = self.rfile.read(content_length) # 解析URL和参数 parsed_url = urlparse(self.path) query_params = parse_qs(parsed_url.query) # 尝试解析JSON数据 json_data = {} if post_data: try: json_data = json.loads(post_data.decode('utf-8')) except json.JSONDecodeError: logger.warning("无法解析POST数据为JSON") # 记录请求信息 logger.info(f"收到POST请求: {self.path}") logger.debug(f"POST数据: {post_data.decode('utf-8')}") logger.debug(f"JSON数据: {json_data}") logger.info(f"URL参数: {query_params}") # 根据路径进行路由 if parsed_url.path == '/api/submit': self._handle_api_submit(query_params, json_data) else: self._handle_not_found() except Exception as e: logger.error(f"处理POST请求时出错: {e}", exc_info=True) self._send_error_response(500, f"服务器内部错误: {str(e)}") def _handle_home(self, params): """处理首页请求""" self._get_logger().info("处理首页请求") response_data = { "message": "欢迎使用Web服务器", "endpoints": { "/": "首页", "/api/data": "获取数据API", "/api/user": "用户信息API", "/api/submit": "提交数据API (POST)", "/health": "健康检查" }, "params_received": params } self._send_json_response(200, response_data) def _handle_api_data(self, params): """处理数据API请求""" logger = self._get_logger() logger.info("处理数据API请求") # 从参数中获取数据 limit = int(params.get('limit', [10])[0]) offset = int(params.get('offset', [0])[0]) filter_type = params.get('type', ['all'])[0] # 模拟数据 data = [ {"id": i + offset, "name": f"Item {i + offset}", "type": filter_type} for i in range(1, limit + 1) ] response_data = { "status": "success", "data": data, "pagination": { "limit": limit, "offset": offset, "total": 100 }, "params_used": { "limit": limit, "offset": offset, "type": filter_type } } logger.debug(f"返回数据: {len(data)} 条记录") self._send_json_response(200, response_data) def _handle_api_user(self, params): """处理用户API请求""" logger = self._get_logger() logger.info("处理用户API请求") user_id = params.get('id', [None])[0] name = params.get('name', [None])[0] if not user_id and not name: self._send_error_response(400, "需要提供id或name参数") return # 模拟用户数据 user_data = { "id": user_id or "123", "name": name or "Unknown", "email": f"{name or 'user'}@example.com" if name else "user@example.com", "role": "user", "status": "active" } response_data = { "status": "success", "user": user_data, "request_params": params } self._send_json_response(200, response_data) def _handle_api_submit(self, params, json_data): """处理提交API请求""" logger = self._get_logger() logger.info("处理提交API请求") # 验证数据 if not json_data: self._send_error_response(400, "需要提供JSON数据") return # 处理提交的数据 response_data = { "status": "success", "message": "数据提交成功", "received_data": json_data, "url_params": params, "timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) } logger.info(f"成功处理提交数据: {json_data}") self._send_json_response(201, response_data) def _handle_health_check(self): """处理健康检查""" self._get_logger().debug("处理健康检查请求") response_data = { "status": "healthy", "service": "Python Web Server", "version": "1.0.0", "timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) } self._send_json_response(200, response_data) def _handle_not_found(self): """处理404错误""" self._get_logger().warning(f"请求的路径不存在: {self.path}") self._send_error_response(404, "请求的路径不存在") def _send_json_response(self, status_code, data): """发送JSON响应""" try: response_json = json.dumps(data, ensure_ascii=False, indent=2) self.send_response(status_code) self.send_header('Content-Type', 'application/json; charset=utf-8') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(response_json.encode('utf-8')) self._get_logger().debug(f"发送响应: 状态码 {status_code}, 数据长度 {len(response_json)}") except Exception as e: self._get_logger().error(f"发送响应时出错: {e}") raise def _send_error_response(self, status_code, message): """发送错误响应""" error_data = { "status": "error", "code": status_code, "message": message } self._get_logger().warning(f"发送错误响应: {status_code} - {message}") self._send_json_response(status_code, error_data) def log_message(self, format, *args): """重写默认的日志方法,使用我们的logger""" self._get_logger().info(format % args) class WebServer: """Web服务器封装类""" def __init__(self, host='', port=8080, logger=None): self.host = host self.port = port self.logger = logger self.httpd = None self.server_thread = None # 初始化web_server的logger if logger: init_web_server(logger) def start(self, daemon=False): """启动服务器""" if self.logger: self.logger.info(f"启动Web服务器,监听端口: {self.port}") self.logger.info(f"服务器地址: http://localhost:{self.port}") self.logger.info("可用端点:") self.logger.info(" GET / - 首页") self.logger.info(" GET /api/data - 获取数据") self.logger.info(" GET /api/user - 用户信息") self.logger.info(" POST /api/submit - 提交数据") self.logger.info(" GET /health - 健康检查") self.httpd = HTTPServer((self.host, self.port), RequestHandler) if daemon: # 在后台线程中运行 self.server_thread = threading.Thread(target=self.httpd.serve_forever, daemon=True) self.server_thread.start() if self.logger: self.logger.info("服务器已在后台线程中启动") else: # 在前台运行 if self.logger: self.logger.info("服务器开始处理请求...") try: self.httpd.serve_forever() except KeyboardInterrupt: self.stop() def stop(self): """停止服务器""" if self.httpd: self.httpd.shutdown() self.httpd.server_close() if self.logger: self.logger.info("服务器已停止") def get_server_address(self): """获取服务器地址""" return f"http://{self.host or 'localhost'}:{self.port}"
log_manager.py
# log_manager.py import logging import logging.handlers import os from datetime import datetime class LogManager: _instance = None _loggers = {} def __new__(cls): if cls._instance is None: cls._instance = super(LogManager, cls).__new__(cls) cls._instance._initialize() return cls._instance def _initialize(self): """初始化日志配置""" self.log_dir = 'logs' os.makedirs(self.log_dir, exist_ok=True) print(f"日志管理器初始化完成,日志目录: {self.log_dir}") def get_logger(self, name='app'): """获取或创建logger""" if name not in self._loggers: logger = logging.getLogger(name) logger.setLevel(logging.INFO) # 清除已有的handler if logger.handlers: logger.handlers.clear() # 创建每日目录 current_date = datetime.now().strftime('%Y-%m-%d') daily_dir = os.path.join(self.log_dir, current_date) os.makedirs(daily_dir, exist_ok=True) # 文件handler - 每小时轮转,最大10MB log_file = os.path.join(daily_dir, f'{name}.log') file_handler = logging.handlers.RotatingFileHandler( log_file, maxBytes=10*1024*1024, backupCount=24, encoding='utf-8' ) # 控制台handler console_handler = logging.StreamHandler() # 格式 formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s' ) file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(console_handler) logger.propagate = False self._loggers[name] = logger print(f"创建logger: {name}") return self._loggers[name] # 创建全局实例 log_manager = LogManager()
main.py
# main.py import argparse import signal import sys from log_manager import log_manager from web_server import WebServer # 获取logger实例 logger = log_manager.get_logger('main') def signal_handler(sig, frame): """处理中断信号""" logger.info("收到中断信号,正在关闭服务器...") if 'server' in globals(): globals()['server'].stop() sys.exit(0) def parse_arguments(): """解析命令行参数""" parser = argparse.ArgumentParser(description='启动Web服务器') parser.add_argument('--port', '-p', type=int, default=8080, help='服务器端口 (默认: 8080)') parser.add_argument('--host', '-H', default='', help='服务器主机 (默认: 所有接口)') parser.add_argument('--daemon', '-d', action='store_true', help='以守护进程模式运行') parser.add_argument('--debug', action='store_true', help='启用调试模式') return parser.parse_args() def setup_server(host, port, debug=False): """设置并返回服务器实例""" # 设置日志级别 if debug: #logger.setLevel(logging.DEBUG) logger.info("调试模式已启用") # 创建服务器实例 server = WebServer(host=host, port=port, logger=logger) return server def main(): """主函数""" # 解析命令行参数 args = parse_arguments() logger.info("=" * 50) logger.info("启动Web服务器应用程序") logger.info(f"主机: {args.host or '所有接口'}") logger.info(f"端口: {args.port}") logger.info(f"守护模式: {args.daemon}") logger.info(f"调试模式: {args.debug}") logger.info("=" * 50) try: # 设置信号处理 signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # 设置服务器 global server server = setup_server(args.host, args.port, args.debug) # 启动服务器 server.start(daemon=args.daemon) # 如果不是守护模式,等待服务器运行 if not args.daemon: logger.info("服务器正在运行,按 Ctrl+C 停止...") #signal.pause() # 等待信号 except Exception as e: logger.error(f"启动服务器时发生错误: {e}", exc_info=True) return 1 return 0 if __name__ == "__main__": # 注册全局server变量,以便信号处理器访问 server = None # 运行主程序 exit_code = main() sys.exit(exit_code)

浙公网安备 33010602011771号