本文目录导读:

我来详细介绍Python脚本中封装请求的命令模式实现方案。
基础命令模式实现
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional
import json
import requests
from dataclasses import dataclass, field
from enum import Enum
# 请求方法枚举
class HttpMethod(Enum):
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
PATCH = "PATCH"
# 命令接口
class Command(ABC):
@abstractmethod
def execute(self) -> Any:
pass
@abstractmethod
def undo(self) -> None:
pass
# 请求数据封装
@dataclass
class RequestData:
url: str
method: HttpMethod
headers: Dict[str, str] = field(default_factory=dict)
params: Dict[str, Any] = field(default_factory=dict)
data: Optional[Dict[str, Any]] = None
json_data: Optional[Dict[str, Any]] = None
timeout: int = 30
def to_dict(self) -> Dict[str, Any]:
return {
'url': self.url,
'method': self.method.value,
'headers': self.headers,
'params': self.params,
'data': self.data,
'json': self.json_data,
'timeout': self.timeout
}
# 响应数据封装
@dataclass
class ResponseData:
status_code: int
headers: Dict[str, str]
content: bytes
elapsed: float
def json(self) -> Dict:
return json.loads(self.content)
def text(self) -> str:
return self.content.decode('utf-8')
# 具体命令类
class HttpRequestCommand(Command):
def __init__(self, request_data: RequestData):
self.request_data = request_data
self.response = None
self.session = requests.Session()
def execute(self) -> ResponseData:
try:
request_dict = self.request_data.to_dict()
method = request_dict.pop('method')
# 发送请求
response = self.session.request(method, **request_dict)
# 封装响应
self.response = ResponseData(
status_code=response.status_code,
headers=dict(response.headers),
content=response.content,
elapsed=response.elapsed.total_seconds()
)
return self.response
except requests.RequestException as e:
raise CommandExecutionError(f"请求执行失败: {str(e)}")
def undo(self) -> None:
"""撤销操作 - 对于HTTP请求,可以记录日志或清理资源"""
if self.response:
print(f"撤销请求: {self.request_data.method.value} {self.request_data.url}")
self.response = None
# 自定义异常
class CommandExecutionError(Exception):
pass
# 命令调用者
class RequestInvoker:
def __init__(self):
self._command = None
self._history = []
def set_command(self, command: Command):
self._command = command
def execute_command(self) -> Any:
if not self._command:
raise ValueError("未设置命令")
result = self._command.execute()
self._history.append(self._command)
return result
def undo_last_command(self) -> None:
if self._history:
command = self._history.pop()
command.undo()
def clear_history(self) -> None:
self._history.clear()
增强版命令模式
import asyncio
from typing import List, Callable, Optional
from functools import wraps
import time
import logging
# 日志装饰器
def log_execution(func: Callable):
@wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"执行命令: {func.__name__}")
start_time = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start_time
logging.info(f"命令完成: {func.__name__}, 耗时: {elapsed:.2f}s")
return result
return wrapper
# 重试机制
def retry(max_retries: int = 3, delay: float = 1.0):
def decorator(func: Callable):
@wraps(func)
def wrapper(*args, **kwargs):
last_exception = None
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
last_exception = e
if attempt < max_retries - 1:
time.sleep(delay * (attempt + 1))
logging.warning(f"重试 {attempt + 1}/{max_retries}")
raise last_exception
return wrapper
return decorator
# 高级请求命令
class AdvancedHttpCommand(Command):
def __init__(self, request_data: RequestData,
max_retries: int = 3,
on_success: Optional[Callable] = None,
on_error: Optional[Callable] = None):
self.request_data = request_data
self.max_retries = max_retries
self.on_success = on_success
self.on_error = on_error
self.response = None
self._retry_count = 0
@log_execution
@retry(max_retries=3)
def execute(self) -> ResponseData:
try:
response = self._send_request()
self.response = response
# 调用成功回调
if self.on_success:
self.on_success(response)
return response
except Exception as e:
# 调用错误回调
if self.on_error:
self.on_error(e)
raise
def _send_request(self) -> ResponseData:
session = requests.Session()
request_dict = self.request_data.to_dict()
method = request_dict.pop('method')
response = session.request(method, **request_dict)
response.raise_for_status() # 检查HTTP状态码
return ResponseData(
status_code=response.status_code,
headers=dict(response.headers),
content=response.content,
elapsed=response.elapsed.total_seconds()
)
def undo(self) -> None:
if self.response:
# 实现撤销逻辑,比如记录日志或缓存清理
logging.info(f"撤销请求: {self.request_data.url}")
self.response = None
# 命令组合器
class CompositeCommand(Command):
def __init__(self, commands: List[Command] = None):
self.commands = commands or []
def add_command(self, command: Command):
self.commands.append(command)
def remove_command(self, command: Command):
self.commands.remove(command)
def execute(self) -> List[Any]:
results = []
for command in self.commands:
result = command.execute()
results.append(result)
return results
def undo(self) -> None:
for command in reversed(self.commands):
command.undo()
# 异步命令
class AsyncHttpCommand(Command):
def __init__(self, request_data: RequestData):
self.request_data = request_data
self.response = None
async def execute_async(self) -> ResponseData:
import aiohttp
async with aiohttp.ClientSession() as session:
async with session.request(
self.request_data.method.value,
self.request_data.url,
headers=self.request_data.headers,
params=self.request_data.params,
json=self.request_data.json_data
) as response:
content = await response.read()
self.response = ResponseData(
status_code=response.status,
headers=dict(response.headers),
content=content,
elapsed=0 # async方式需要额外计算
)
return self.response
def execute(self) -> ResponseData:
# 同步方式的回调
return asyncio.run(self.execute_async())
def undo(self) -> None:
self.response = None
# 命令工厂
class CommandFactory:
@staticmethod
def create_get_request(url: str, params: Dict = None, headers: Dict = None) -> HttpRequestCommand:
request_data = RequestData(
url=url,
method=HttpMethod.GET,
params=params or {},
headers=headers or {}
)
return HttpRequestCommand(request_data)
@staticmethod
def create_post_request(url: str, json_data: Dict, headers: Dict = None) -> HttpRequestCommand:
request_data = RequestData(
url=url,
method=HttpMethod.POST,
json_data=json_data,
headers=headers or {}
)
return HttpRequestCommand(request_data)
@staticmethod
def create_advanced_command(request_data: RequestData, **kwargs) -> AdvancedHttpCommand:
return AdvancedHttpCommand(request_data, **kwargs)
使用示例
def example_usage():
# 1. 基本使用
invoker = RequestInvoker()
# 创建GET请求
get_command = CommandFactory.create_get_request(
url="https://api.example.com/users",
params={"page": 1},
headers={"Authorization": "Bearer token123"}
)
invoker.set_command(get_command)
try:
response = invoker.execute_command()
print(f"状态码: {response.status_code}")
print(f"响应内容: {response.text()}")
except CommandExecutionError as e:
print(f"错误: {e}")
# 2. 高级使用
request_data = RequestData(
url="https://api.example.com/users",
method=HttpMethod.POST,
json_data={"name": "John", "age": 30},
headers={"Content-Type": "application/json"}
)
def on_success(response):
print(f"请求成功: {response.status_code}")
def on_error(error):
print(f"请求失败: {error}")
advanced_command = CommandFactory.create_advanced_command(
request_data,
max_retries=3,
on_success=on_success,
on_error=on_error
)
invoker.set_command(advanced_command)
result = invoker.execute_command()
# 3. 批量请求
composite = CompositeCommand()
# 添加多个请求
commands = [
CommandFactory.create_get_request("https://api.example.com/endpoint1"),
CommandFactory.create_get_request("https://api.example.com/endpoint2"),
CommandFactory.create_get_request("https://api.example.com/endpoint3")
]
for cmd in commands:
composite.add_command(cmd)
# 执行批量请求
results = composite.execute()
# 4. 撤销操作
invoker.undo_last_command()
配置文件支持
import yaml
from pathlib import Path
# 配置加载
class CommandConfig:
def __init__(self, config_path: str = "requests.yaml"):
self.config = self._load_config(config_path)
def _load_config(self, path: str) -> Dict:
with open(path, 'r') as f:
return yaml.safe_load(f)
def create_commands_from_config(self) -> List[Command]:
commands = []
for request_config in self.config.get('requests', []):
request_data = RequestData(
url=request_config['url'],
method=HttpMethod[request_config['method']],
headers=request_config.get('headers', {}),
params=request_config.get('params', {}),
json_data=request_config.get('json_data'),
timeout=request_config.get('timeout', 30)
)
commands.append(HttpRequestCommand(request_data))
return commands
# 示例YAML配置文件
"""
requests:
- url: "https://api.example.com/users"
method: GET
headers:
Authorization: "Bearer token"
params:
page: 1
limit: 10
- url: "https://api.example.com/users"
method: POST
json_data:
name: "John"
age: 30
timeout: 10
"""
核心优势:
- 解耦:请求的发送者与接收者完全解耦
- 可扩展:易于添加新的命令类型
- 可回滚:支持撤销操作
- 可组合:支持命令组合和批处理
适用场景:
- 需要记录请求历史
- 需要支持请求重试
- 需要批量处理请求
- 需要支持事务性操作
这个模式特别适合API客户端、爬虫系统、微服务调用等需要处理大量HTTP请求的场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播