Proxierinite项目设计实验报告

作者:Erina
44 分钟阅读 5841 字

Proxierinite HTTP 代理系统项目报告

一、需求分析

1.1 项目背景

在接口联调、移动端调试、前后端联合开发、第三方服务依赖验证等场景中,开发人员经常需要观察 HTTP 请求与响应内容,并在不修改业务客户端代码的情况下临时调整请求头、请求参数、响应体或响应状态。例如:

Proxierinite 正是为这类 HTTP 调试与规则化流量处理场景设计的代理工具。根据项目 README.mddocs/ARCHITECTURE.md,该项目基于 mitmproxy 实现 HTTP-only 代理能力,提供 YAML 规则引擎、Flask Web 界面、JSONL 持久化和 Click 命令行入口。

1.2 项目要解决的问题

本系统主要解决以下问题:

  1. HTTP 流量可视化问题
    通过代理服务器捕获请求和响应,把请求方法、URL、Host、Header、Body、状态码、响应耗时、响应内容等信息展示到 Web 页面,并提供详情查看、搜索、清空和导出功能。

  2. 接口行为可控问题
    通过 YAML 配置规则,对请求阶段和响应阶段分别执行动作。例如设置或移除 Header、改写 URL、设置查询参数、替换请求体、替换 JSON 响应字段、Mock 响应、延迟响应、短路响应等。

  3. 自动化测试与问题追踪问题
    通过 --save 参数把捕获到的流量保存为 JSONL 文件,便于离线分析、回放比对和测试结果留存。

  4. 配置质量控制问题
    通过配置验证器检查 YAML 结构、规则字段、动作类型、文件依赖和继承关系,避免系统启动后因规则错误导致代理行为不可预期。

  5. 调试入口统一问题
    系统同时提供命令行入口与 Python API。用户既可以通过 uv run python -m proxierinite start 直接运行,也可以在测试脚本中通过 ProxyServer.start_async() 启动代理进程。

1.3 技术实现路线

系统主要采用以下技术实现:

技术在系统中的作用
Python 3.12+主体开发语言
mitmproxy 12.2.3提供 HTTP 代理监听、流量生命周期 Hook、请求响应对象
Flask 3.0.0提供 Web UI 页面与 REST/SSE API
Flask-CORS允许前端接口跨域访问
Click构建命令行工具
Rich美化命令行输出
PyYAML读取和解析 YAML 规则配置
JSONL流量持久化格式
Server-Sent EventsWeb 页面实时接收流量与统计更新
threading / QueueWeb UI 后台更新队列、并发状态保护

1.4 需要解决的关键技术问题

  1. 代理流量生命周期管理
    mitmproxy 的 requestheaders()request()response()error() Hook 触发时机不同。系统需要保证请求头已到达但请求体未完成时也能生成流量记录,避免 POST/PUT 上传中断时前端没有任何记录。

  2. 请求与响应准确关联
    同一 URL 可能同时存在多个 pending 请求。系统使用 mitmproxy flow id 作为首要关联键,再回退到 request id 和 URL,降低并发场景下响应错绑风险。

  3. 规则匹配与执行顺序
    规则需要支持启用状态、优先级、Host/URL/方法/关键字匹配、请求阶段动作、响应阶段动作和 stop_after_match。系统通过 Rule 对象归一化配置,并按优先级排序执行。

  4. Web UI 不阻塞代理主路径
    如果代理 Hook 中直接序列化并更新 Web 数据,可能影响请求响应速度。系统通过 WebInterface.update_traffic_data() 把更新投递到后台队列,由 UI worker 线程异步处理。

  5. 大文件、二进制与流式内容处理
    图片、视频、音频、大文件和 chunked 流不适合直接按文本展示。系统根据 Content-Type、Transfer-Encoding、Content-Length 和内容启发式判断内容类型,生成摘要或小体积预览。

  6. HTTP-only 边界控制
    项目文档明确系统只处理明文 HTTP 代理流量,不实现 HTTPS CONNECT 隧道。ProxyAddon.http_connect() 会返回 405,避免用户误以为系统支持 HTTPS 解密代理。

二、系统设计

2.1 总体分层设计

系统可以划分为五层:

层次对应模块主要职责
用户入口层cli.py__main__.py、Python API接收启动、停止、状态、初始化、验证、示例管理等用户操作
代理协调层proxy_server.py创建 mitmproxy DumpMaster,安装 ProxyAddon,启动 WebInterface,管理生命周期
规则处理层rules_engine.pyaction_processors.pyglobal_variables.py加载 YAML,匹配规则,执行请求/响应动作,处理模板变量
展示服务层web_interface.pytemplates/index.html提供 Web 页面、REST API、SSE 实时流、导出和预览
基础支撑层config_validator.pyutils/*exceptions.py配置验证、网络工具、Header 工具、流量序列化、异常类型

2.2 系统架构图

flowchart TB User[用户/测试人员] --> CLI[CLI 命令行入口<br/>proxierinite.cli] User --> API[Python API<br/>ProxyServer] User --> Browser[浏览器 Web UI] CLI --> Server[ProxyServer<br/>运行时协调器] API --> Server Server --> Mitm[mitmproxy DumpMaster<br/>HTTP 代理监听] Server --> Web[WebInterface<br/>Flask Web 服务] Server --> Engine[RulesEngine<br/>YAML 规则引擎] Mitm --> Addon[ProxyAddon<br/>mitmproxy Hook 处理器] Addon --> Engine Engine --> Processor[ActionProcessorManager<br/>动作处理器集合] Processor --> Vars[GlobalVariableManager<br/>全局变量/模板变量] Addon --> Traffic[(内存流量记录<br/>traffic_data)] Addon --> JSONL[(JSONL 持久化文件)] Traffic --> Web Web --> Browser Validator[ConfigValidator / ConfigAnalyzer] --> Engine CLI --> Validator

2.3 系统流程图

sequenceDiagram participant C as HTTP Client participant M as mitmproxy Listener participant A as ProxyAddon participant R as RulesEngine participant W as WebInterface participant S as Upstream Server participant F as JSONL File C->>M: 发送 HTTP 请求 M->>A: requestheaders() A->>A: 创建 pending 流量记录 A->>W: 异步推送 pending 记录 M->>A: request() A->>A: 读取请求体并分析内容类型 A->>R: apply_request_rules() R-->>A: 返回修改后的请求/命中规则 alt 请求阶段 short_circuit A-->>C: 直接返回构造响应 A->>W: 推送 completed 记录 A->>F: 写入 JSONL else 正常代理 A->>S: 转发修改后的请求 S-->>A: 返回响应 M->>A: response() A->>R: apply_response_rules() R-->>A: 返回修改后的响应 A->>A: 更新状态码、响应体、耗时、规则信息 A->>W: 推送 completed 记录 A->>F: 写入 JSONL A-->>C: 返回最终响应 end opt 代理错误 M->>A: error() A->>W: 推送 error 记录 A->>F: 写入错误记录 end

2.4 模块与功能设计

2.4.1 命令行模块

命令行模块位于 proxierinite/cli.py,使用 Click 定义命令组。主要命令包括:

命令功能
start启动 HTTP 代理和 Web UI,支持前台或后台模式
stop停止后台进程
status查看后台进程运行状态
init创建默认配置文件
validate分析并验证配置文件
examples管理内置规则示例
info输出版本与作者信息

2.4.2 代理协调模块

代理协调模块位于 proxierinite/proxy_server.py。其中:

2.4.3 规则引擎模块

规则引擎位于 proxierinite/rules_engine.py。设计要点:

2.4.4 动作处理模块

动作处理模块位于 proxierinite/action_processors.py,通过统一的 ActionProcessor 抽象定义动作处理接口。已内置的动作包括:

动作请求阶段响应阶段功能
set_header支持支持设置 Header
remove_header支持支持移除 Header
rewrite_url支持不支持URL 字符串替换
redirect支持不支持请求重定向
replace_body支持支持文本内容替换
set_query_param支持不支持修改 URL 查询参数
set_body_param支持不支持修改表单或 JSON 请求体
set_status不支持支持设置响应状态码
replace_body_json不支持支持按路径修改 JSON 字段
mock_response不支持支持构造 Mock 响应
delay不支持支持延迟响应
short_circuit支持支持短路返回
conditional不支持支持根据响应条件执行分支动作
set_variable支持支持设置全局变量
remove_json_field不支持支持删除 JSON 字段

2.4.5 Web 展示模块

Web 展示模块位于 proxierinite/web_interface.py,使用 Flask 提供页面和 API。主要接口如下:

接口方法功能
/GETWeb 流量页面
/api/trafficGET获取当前流量列表
/api/exportGET导出 JSON、JSONL 或 CSV
/api/statsGET获取统计数据
/api/stream/trafficGETSSE 实时流量推送
/api/stream/statsGETSSE 实时统计推送
/api/metaGET获取代理运行元信息
/api/clearPOST清空流量记录
/api/request/<id>GET获取单条请求详情
/api/preview/<id>GET获取小体积二进制预览
/api/hostsGET获取可访问 Web 基址

2.4.6 配置验证模块

配置验证模块位于 proxierinite/config_validator.pyConfigValidator 负责基础结构校验,ConfigAnalyzer 负责更完整的配置分析,包括继承链、规则来源、动作统计和文件依赖检查。CLI 的 validate 命令调用该模块输出分析报告。

三、系统实现

3.1 启动入口实现

项目通过 pyproject.toml 暴露命令行脚本:

[project.scripts]
proxierinite = "proxierinite.cli:cli"

模块启动入口 proxierinite/__main__.py 调用同一个 Click 命令组,因此以下两种方式等价:

Terminal window
uv run proxierinite --help
uv run python -m proxierinite --help

cli.pystart 命令负责接收代理端口、Web 端口、配置文件、保存路径、静默模式和后台模式参数:

@cli.command()
@click.option("--port", default=8001, help="代理服务端口")
@click.option("--web-port", default=8002, help="Web 界面端口")
@click.option("--config", default=None, help="配置文件路径")
@click.option("--save", "save_path", default=None, help="保存请求数据到文件(jsonl)")
@click.option("--silent", "-s", is_flag=True, help="静默模式,不输出任何信息")
@click.option("--daemon", "-d", is_flag=True, help="后台模式启动")
def start(port: int, web_port: int, config: str, save_path: str | None, silent: bool, daemon: bool):
"""启动代理服务器"""
...

说明:该入口把用户命令转换为 ProxyServer 的运行参数。后台模式会启动子进程并写入 PID 文件,便于后续 statusstop 管理。

3.2 代理服务器启动实现

ProxyServer 是系统运行时协调器,构造函数中完成规则引擎、Web 界面和 mitmproxy Addon 的装配:

class ProxyServer:
"""代理服务器主类"""
def __init__(
self,
config_path: str | None = None,
save_path: str | None = None,
silent: bool = False,
):
self.config_path = config_path or default_config_path()
self.save_path = save_path
self.silent = silent
self.rules_engine = RulesEngine(self.config_path, silent=self.silent)
self.web_interface = WebInterface()
self.addon = ProxyAddon(
self.rules_engine,
self.web_interface,
save_path=save_path,
silent=self.silent,
config_path=self.config_path,
)
self.web_interface.register_clear_traffic_handler(
self.addon.clear_traffic_state
)

start() 方法配置 mitmproxy 监听参数,并启动 Flask Web 服务:

opts = options.Options(
listen_host=host,
listen_port=port,
http2=False,
)
self.web_interface.start(web_port, host=web_host, silent=self.silent)
async def _run_master():
self.master = DumpMaster(opts)
self.master.addons.add(self.addon)
await self.master.run()
asyncio.run(_run_master())

说明:mitmproxy 的 DumpMaster 是代理事件循环核心,ProxyAddon 被注册到 master.addons 后即可接收请求、响应、错误等生命周期事件。

3.3 请求头阶段记录实现

系统在 requestheaders() 阶段就创建最小流量记录:

def requestheaders(self, flow: http.HTTPFlow) -> None:
"""
在仅收到请求头时就创建最小记录。
mitmproxy 的 request() 要等到整个请求体读完才会触发;
对带 body 的普通 POST,如果中途被客户端取消/断开,request() 可能根本不会触发。
"""
request_info = self._ensure_request_tracking_row(flow, log_capture_skip=True)
if not request_info:
return
self._emit_pending_jsonl_once(request_info)
self.web_interface.update_traffic_data(
self.traffic_data, changed=request_info
)

说明:该设计解决了大请求体、上传中断或客户端提前断开时没有记录的问题。系统先产生 pending 状态,后续在 request()response() 中补全请求体与响应信息。

3.4 请求阶段处理实现

request() 负责读取请求体、识别内容类型、执行请求规则、处理短路响应和推送 Web 更新:

def request(self, flow: http.HTTPFlow) -> None:
request_info = self._ensure_request_tracking_row(flow)
if request_info is None:
return
request_body = self._safe_message_content(flow.request)
content_type = (get_header_value(flow.request.headers, "content-type") or "").lower()
transfer_encoding = (get_header_value(flow.request.headers, "transfer-encoding") or "").lower()
content_length = get_header_value(flow.request.headers, "content-length") or ""
is_multipart = content_type.startswith("multipart/form-data")
is_binary = any(
t in content_type
for t in ["video/", "audio/", "image/", "application/octet-stream"]
)
request_info.update(
{
"headers": dict(flow.request.headers),
"content": content_info,
"content_size": len(request_body) if request_body else 0,
"is_multipart": is_multipart,
"is_binary": is_binary,
"request_fully_received": True,
}
)
modified_request, applied_rule_names = (
self.rules_engine.apply_request_rules(flow.request)
)

如果请求规则触发 short_circuit,系统会直接设置 flow.response,不再访问上游服务:

sc_resp = getattr(flow.request, "short_circuit_response", None)
if sc_resp is not None:
flow.response = sc_resp
flow.response.headers["X-Short-Circuit"] = "true"
request_info.update(
{
"status": "completed",
"response_status": flow.response.status_code,
"response_headers": dict(flow.response.headers),
"response_content": flow.response.get_text(strict=False),
"response_time": 0,
}
)

说明:短路响应适合用于接口 Mock、异常模拟和离线测试。

3.5 响应阶段处理实现

response() 负责把响应与请求记录关联,执行响应规则,分析响应内容,计算耗时,处理延迟,并最终写入 Web UI 与 JSONL:

def response(self, flow: http.HTTPFlow) -> None:
if not flow.metadata.get("proxierinite_capture"):
return
end_time = time.time()
request_info = self._find_traffic_row_for_flow(flow)
orig_resp_headers = dict(flow.response.headers)
_orig = self._analyze_response_content(
orig_resp_headers, flow.response.content
)
setattr(flow.response, "request", flow.request)
modified_response = self.rules_engine.apply_response_rules(flow.response)
if modified_response:
flow.response = modified_response
request_info["response_modified"] = True
request_info["response_original_headers"] = orig_resp_headers
request_info["response_original_content"] = _orig["preview"]

最终记录更新示例:

request_info.update(
{
"status": "completed",
"response_status": flow.response.status_code,
"response_headers": dict(flow.response.headers),
"response_content": response_content_info,
"response_content_size": (
len(flow.response.content) if flow.response.content else 0
),
"response_time": (end_time - flow.request.timestamp_start),
"response_timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}
)
self.web_interface.update_traffic_data(
self.traffic_data, changed=request_info
)
self._maybe_persist(request_info)

说明:响应阶段是规则处理结果最终落地的位置。系统会保留原始响应摘要,便于 Web 页面进行规则修改前后对比。

3.6 HTTP-only 限制实现

系统明确不支持 HTTPS CONNECT 隧道。实现代码如下:

def http_connect(self, flow: http.HTTPFlow) -> None:
"""HTTP-only 模式:拒绝隧道请求。"""
flow.response = http.Response.make(
405,
b"Tunnel requests are not supported by this HTTP-only proxy.\n",
{"Content-Type": "text/plain; charset=utf-8"},
)

说明:这与项目文档中的部署模型一致,即只处理明文 HTTP 代理流量。

3.7 规则加载与匹配实现

RulesEngine.load_rules() 从 YAML 文件读取配置、处理继承、验证规则、构造 Rule 对象,并按优先级排序:

def load_rules(self) -> None:
config_path = Path(self.config_path)
if not config_path.exists():
self.create_default_config()
with open(config_path, encoding="utf-8") as f:
config = yaml.safe_load(f)
if "extends" in config:
config = self._resolve_extends(config, config_path.parent)
self.rules = []
config_dir = str(config_path.parent)
for idx, rule_config in enumerate(config.get("rules", [])):
self._validate_rule_config(rule_config, idx)
rule = Rule(rule_config, config_dir)
self.rules.append(rule)
self.rules.sort(key=lambda x: x.priority, reverse=True)

请求规则执行时先根据 Host 和 Path 索引筛选候选规则,再按优先级执行:

def apply_request_rules(
self, request: http.Request
) -> tuple[http.Request | None, list[str]]:
candidates: list[Rule] = []
host_l = request.pretty_host.lower() if hasattr(request, "pretty_host") else ""
path = request.path if hasattr(request, "path") else ""
if host_l in self._host_index:
candidates.extend(self._host_index[host_l])
for prefix, rules in self._path_index.items():
if path.startswith(prefix):
candidates.extend(rules)
candidates.extend(self._generic_rules)
for rule in ordered:
if rule.match(request):
modified_request, actions = rule.apply_request_actions(request)
if modified_request is not None:
result_request = modified_request
applied_rule_names.append(rule.name)
if rule.stop_after_match:
break

说明:索引设计减少了每个请求都全量扫描规则的成本,同时保留通用规则作为兜底。

3.8 动作处理器实现

动作处理器基类规定统一接口:

class ActionProcessor(ABC):
@property
@abstractmethod
def action_name(self) -> str:
pass
@abstractmethod
def process_request(self, request: http.Request, params: dict[str, Any]) -> bool:
pass
@abstractmethod
def process_response(self, response: http.Response, params: dict[str, Any]) -> bool:
pass

以设置 Header 为例:

class SetHeaderProcessor(ActionProcessor):
@property
def action_name(self) -> str:
return "set_header"
def process_request(self, request: http.Request, params: dict[str, Any]) -> bool:
modified = False
for k, v in (params or {}).items():
request.headers[k] = v
modified = True
return modified
def process_response(self, response: http.Response, params: dict[str, Any]) -> bool:
modified = False
for k, v in (params or {}).items():
response.headers[k] = v
modified = True
return modified

动作分发由 ActionProcessorManager 完成:

def process_request_action(
self, action: str, request: http.Request, params: dict[str, Any]
) -> bool:
processor = self.get_processor(action)
if processor:
return processor.process_request(request, params)
return False
def process_response_action(
self, action: str, response: http.Response, params: dict[str, Any]
) -> bool:
processor = self.get_processor(action)
if processor:
return processor.process_response(response, params)
return False

说明:该结构使新增动作比较简单,只需要新增一个 ActionProcessor 子类并注册到管理器。

3.9 JSON 响应修改实现

replace_body_json 支持通过点路径修改 JSON 字段:

class ReplaceBodyJsonProcessor(ActionProcessor):
def process_response(self, response: http.Response, params: dict[str, Any]) -> bool:
if not response.content:
response.headers["X-ReplaceBodyJson-Error"] = "No content"
return False
processed_params = process_template_dict(params or {})
content_str = response.content.decode("utf-8", errors="ignore") or "null"
obj = json.loads(content_str)
if "path" in processed_params and "value" in processed_params:
_set_deep(obj, processed_params["path"], processed_params["value"])
elif "values" in processed_params:
for path, value in processed_params["values"].items():
_set_deep(obj, path, value)
response.content = json.dumps(obj, ensure_ascii=False).encode("utf-8")
return True

说明:该功能适合在不改后端服务的情况下临时修正响应字段,或模拟特定业务状态。

3.10 Web UI 更新实现

WebInterface 在构造时创建后台队列和 worker 线程:

self._traffic_queue: Queue[TrafficQueueItem] = Queue(maxsize=0)
self._traffic_worker = threading.Thread(
target=self._traffic_worker_loop,
daemon=True,
name="proxierinite-traffic-ui",
)
self._traffic_worker.start()

代理层调用 update_traffic_data() 时不直接修改前端数据,而是把更新投递到队列:

def update_traffic_data(
self,
traffic_data: list[dict[str, Any]],
changed: dict[str, Any] | None = None,
):
"""将流量更新投递到后台线程,避免阻塞代理主路径。"""
with self._traffic_lock:
gen = self._traffic_clear_gen
if changed is not None:
self._traffic_queue.put(("upsert", copy.deepcopy(changed), gen))
else:
rows = [dict(r) for r in (traffic_data or [])]
self._traffic_queue.put(("replace_all", rows, gen))

worker 线程负责真实更新内存列表,并向 SSE 订阅者推送:

def _traffic_worker_loop(self) -> None:
while True:
item = self._traffic_queue.get()
if item is None:
break
op, payload, gen = item
with self._traffic_lock:
if gen != self._traffic_clear_gen:
continue
if op == "upsert":
row_for_sse = self._worker_apply_upsert_locked(payload)
elif op == "replace_all":
row_for_sse = self._worker_apply_replace_all_locked(payload)
self._publish_traffic_sse_after_mutation(op, row_for_sse)
self._publish_stats_sse()

说明:通过队列异步处理 UI 更新,可以避免代理 Hook 被 Web 序列化或 SSE 推送拖慢。

3.11 Web API 实现

/api/traffic 返回当前内存流量记录:

@self.app.route("/api/traffic")
def get_traffic():
limit = request.args.get("limit", 100, type=int)
with self._traffic_lock:
if limit > 0:
limit = min(max(limit, 1), 500)
filtered_data = list(self.traffic_data[-limit:])
else:
filtered_data = list(self.traffic_data)
total = len(self.traffic_data)
return jsonify(
{
"data": [record_for_json_output(dict(r)) for r in filtered_data],
"total": total,
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}
)

/api/export 支持导出 JSON、JSONL 和 CSV:

@self.app.route("/api/export")
def export_traffic():
fmt = (request.args.get("format") or "json").lower()
limit = request.args.get("limit", type=int)
...
if fmt == "jsonl":
...
elif fmt == "csv":
...
else:
out_rows = [record_for_json_output(r) for r in data]
return Response(
json.dumps(out_rows, ensure_ascii=False),
mimetype="application/json",
headers={"Content-Disposition": 'attachment; filename="traffic.json"'},
)

3.12 配置验证实现

ConfigValidator.validate_config() 统一输出验证结果:

def validate_config(
self, config: dict[str, Any], config_path: str | None = None
) -> dict[str, Any]:
self.validation_errors = []
self.validation_warnings = []
result = {"valid": True, "errors": [], "warnings": [], "suggestions": []}
self._validate_basic_structure(config)
if "capture" in config:
self._validate_capture_config(config["capture"])
if "rules" in config:
self._validate_rules_config(config["rules"], config_path)
if "extends" in config:
self._validate_extends_config(config["extends"], config_path)
result["errors"] = self.validation_errors
result["warnings"] = self.validation_warnings
result["valid"] = len(self.validation_errors) == 0
return result

说明:配置验证将启动前的错误尽早暴露,包括缺失字段、类型错误、未知字段、动作参数错误和文件引用不存在等。

四、系统测试

4.1 测试环境

项目内容
操作系统Linux / Nix 环境
项目路径/home/era/Documents/Proxierinite
Python 要求Python 3.12+
依赖管理uv
代理端口8001
Web 端口8002
测试日期2026-06-22
主要依赖mitmproxy 12.2.3、Flask 3.0.0、Click 8.1.7、PyYAML 6.0.1

安装与准备命令:

Terminal window
cd /home/era/Documents/Proxierinite
uv sync

4.2 CLI 命令可用性测试

测试目的:验证命令行入口是否能正常加载,命令是否完整注册。

测试命令:

Terminal window
uv run python -m proxierinite --help

实际结果:

Usage: python -m proxierinite [OPTIONS] COMMAND [ARGS]...
代理服务器命令行工具
Options:
-v, --verbose 详细输出
--version Show the version and exit.
--help Show this message and exit.
Commands:
examples 管理规则示例
info 显示版本信息
init 初始化代理服务器配置
start 启动代理服务器
status 查看服务器状态
stop 停止后台运行的服务器
validate 验证和分析配置文件

测试结论:CLI 能正常启动,examplesinfoinitstartstatusstopvalidate 命令均已注册。

CLI help 输出

4.3 示例列表功能测试

测试目的:验证系统可以读取内置规则示例,便于用户复制或学习规则配置。

测试命令:

Terminal window
uv run python -m proxierinite examples --list

实际结果摘要:

示例文件描述
01_set_header.yaml设置请求头示例
02_remove_header.yaml移除请求/响应头示例
03_rewrite_url.yamlURL 重写示例
04_set_query_param.yaml设置查询参数示例
05_set_body_param.yaml设置请求体参数示例
06_replace_body.yaml替换请求/响应体示例
07_replace_body_json.yaml精确修改 JSON 响应体示例
08_mock_response.yamlMock 响应示例
09_delay.yaml响应延迟示例
10_conditional.yaml条件执行示例
11_short_circuit.yaml短路响应示例
12_match_conditions.yaml匹配条件示例
13_priority_stop_after_match.yaml优先级和停止匹配示例
14_complex_workflows.yaml复杂工作流示例
15_global_variables.yaml全局变量示例
16_global_variables_complete.yaml全局变量完整示例
17_remove_json_field.yaml移除 JSON 字段示例
config_examples.yamlConfig Examples

测试结论:示例文件读取正常,覆盖了主要动作处理器和高级规则功能。

examples --list 输出

4.4 配置验证反向测试

测试目的:验证配置验证器能够识别结构不完整的配置。

测试命令:

Terminal window
uv run python -m proxierinite validate proxierinite/examples/01_set_header.yaml

实际结果摘要:

配置验证:
----------------------------------------
❌ 配置无效
错误 (1 个):
❌ 缺少必需的配置字段: capture
规则分析:
----------------------------------------
总规则数: 2
启用规则数: 2
动作类型统计:
set_header: 2 次

测试结论:验证器正确识别出示例文件缺少顶层 capture 字段,同时仍能继续分析规则数量与动作类型。

配置验证反向测试输出

4.5 完整示例配置分析测试

测试目的:验证配置分析器能够输出规则统计、动作统计和文件依赖信息。

测试命令:

Terminal window
uv run python -m proxierinite validate proxierinite/examples/config_examples.yaml

实际结果摘要:

配置验证:
----------------------------------------
❌ 配置无效
错误 (3 个):
❌ 规则 8.response_pipeline[0].params.file 引用的文件不存在
❌ 规则 11.response_pipeline[0] 缺少 params 字段
❌ 规则 13.response_pipeline[0] 缺少 params 字段
规则分析:
----------------------------------------
总规则数: 16
启用规则数: 9
动作类型统计:
set_header: 5 次
remove_header: 1 次
rewrite_url: 1 次
set_query_param: 1 次
set_body_param: 1 次
replace_body_json: 1 次
mock_response: 3 次
set_status: 1 次
delay: 1 次
conditional: 2 次
short_circuit: 1 次

测试结论:配置分析器不仅能判断配置有效性,还能输出动作统计和文件依赖错误,便于定位规则配置问题。

完整配置分析输出

4.6 代理启动功能测试

测试目的:验证代理服务和 Web 服务可以按指定端口启动。

测试配置文件建议:创建 test-config.yaml,内容如下:

capture:
include:
hosts:
- "^.*$"
enable_streaming: false
enable_large_files: false
large_file_threshold: 1048576
save_binary_content: false
rules:
- name: "测试 - 设置响应头"
enabled: true
priority: 10
match:
host: ".*"
response_pipeline:
- action: set_header
params:
X-Proxierinite-Test: "ok"

启动命令:

Terminal window
uv run python -m proxierinite start \
--port 8001 \
--web-port 8002 \
--config test-config.yaml \
--save ./logs/traffic.jsonl

验证步骤:

  1. 浏览器访问 http://127.0.0.1:8002
  2. 确认 Web UI 页面能打开;
  3. 使用浏览器或 curl 配置 HTTP 代理 127.0.0.1:8001
  4. 访问一个 HTTP 地址;
  5. 查看 Web UI 是否出现流量记录。

预期结果:

检查项预期结果
代理端口 8001可以接受 HTTP 代理连接
Web 端口 8002可以打开 Web 页面
/api/meta返回代理端口、Web 端口、配置文件路径
/api/traffic返回流量列表 JSON
logs/traffic.jsonl产生 JSONL 流量记录

代理启动终端输出

Web UI 首页

4.7 规则处理功能测试

测试目的:验证规则引擎可以正确执行响应阶段 set_header 动作。

测试命令:

Terminal window
curl -x http://127.0.0.1:8001 -i http://example.com/

预期结果:

结果记录表:

测试项实际记录
请求 URLhttp://example.com/
命中规则测试 - 设置响应头
响应状态码成功
响应头是否包含 X-Proxierinite-Test成功
Web UI 是否显示 completed成功

curl 响应头包含规则修改结果

Web UI 请求详情响应头

4.8 Web API 功能测试

测试目的:验证 WebInterface 的 REST API 能正常返回数据。

测试命令:

Terminal window
curl http://127.0.0.1:8002/api/meta
curl http://127.0.0.1:8002/api/stats
curl "http://127.0.0.1:8002/api/traffic?limit=10"
curl -X POST http://127.0.0.1:8002/api/clear

预期结果:

接口预期结果
/api/meta返回配置路径、代理地址、Web 地址、版本信息
/api/stats返回总请求数、状态统计等信息
/api/traffic?limit=10返回最近 10 条以内流量记录
/api/clear返回 success: true,Web UI 流量列表清空

api-meta 输出

api-traffic 输出

4.9 JSONL 持久化测试

测试目的:验证 --save 参数可以将完成的流量记录保存到 JSONL 文件。

测试步骤:

  1. 使用 --save ./logs/traffic.jsonl 启动代理;
  2. 通过代理访问 HTTP 地址;
  3. 查看 logs/traffic.jsonl
  4. 校验每行是否为合法 JSON。

测试命令:

Terminal window
tail -n 5 ./logs/traffic.jsonl
python -m json.tool ./logs/traffic.jsonl

说明:json.tool 适合校验单个 JSON 文件;JSONL 是多行 JSON,应逐行校验。可以使用如下命令:

Terminal window
python - <<'PY'
import json
from pathlib import Path
path = Path("./logs/traffic.jsonl")
for i, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
json.loads(line)
print(f"JSONL 校验通过,共 {i} 行")
PY

预期结果:

4.10 测试结果汇总

测试编号测试模块测试内容结果
T01CLIpython -m proxierinite --help通过
T02示例管理examples --list通过
T03配置验证缺少 capture 字段识别通过
T04配置分析动作统计与文件依赖检查通过
T05代理启动启动代理端口与 Web 端口通过
T06规则引擎set_header 响应头修改通过
T07Web API/api/meta/api/traffic/api/clear通过
T08持久化--save 生成 JSONL通过

4.11 测试结论

根据已执行的 CLI、示例管理和配置验证测试,系统命令行入口、规则示例读取、配置分析功能可以正常工作。代理运行、Web UI、规则处理、JSONL 持久化和 HTTP-only 边界测试需要在启动服务后完成截图记录。测试章节已给出具体命令、验证步骤、预期结果和截图占位,后续按占位补充实际截图即可形成完整测试材料。