Proxierinite项目设计实验报告
Proxierinite HTTP 代理系统项目报告
一、需求分析
1.1 项目背景
在接口联调、移动端调试、前后端联合开发、第三方服务依赖验证等场景中,开发人员经常需要观察 HTTP 请求与响应内容,并在不修改业务客户端代码的情况下临时调整请求头、请求参数、响应体或响应状态。例如:
- 前端需要在后端接口未完成时使用 Mock 响应继续开发;
- 测试人员需要模拟接口延迟、异常状态码、重定向等场景;
- 开发人员需要查看真实 HTTP 流量,定位请求参数、响应内容、Header 配置问题;
- 自动化测试需要把代理流量落盘,形成可追溯的 JSONL 测试数据;
- 多个规则需要按优先级组合执行,并支持命中后停止后续规则。
Proxierinite 正是为这类 HTTP 调试与规则化流量处理场景设计的代理工具。根据项目 README.md 与 docs/ARCHITECTURE.md,该项目基于 mitmproxy 实现 HTTP-only 代理能力,提供 YAML 规则引擎、Flask Web 界面、JSONL 持久化和 Click 命令行入口。
1.2 项目要解决的问题
本系统主要解决以下问题:
-
HTTP 流量可视化问题
通过代理服务器捕获请求和响应,把请求方法、URL、Host、Header、Body、状态码、响应耗时、响应内容等信息展示到 Web 页面,并提供详情查看、搜索、清空和导出功能。 -
接口行为可控问题
通过 YAML 配置规则,对请求阶段和响应阶段分别执行动作。例如设置或移除 Header、改写 URL、设置查询参数、替换请求体、替换 JSON 响应字段、Mock 响应、延迟响应、短路响应等。 -
自动化测试与问题追踪问题
通过--save参数把捕获到的流量保存为 JSONL 文件,便于离线分析、回放比对和测试结果留存。 -
配置质量控制问题
通过配置验证器检查 YAML 结构、规则字段、动作类型、文件依赖和继承关系,避免系统启动后因规则错误导致代理行为不可预期。 -
调试入口统一问题
系统同时提供命令行入口与 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 Events | Web 页面实时接收流量与统计更新 |
| threading / Queue | Web UI 后台更新队列、并发状态保护 |
1.4 需要解决的关键技术问题
-
代理流量生命周期管理
mitmproxy 的requestheaders()、request()、response()、error()Hook 触发时机不同。系统需要保证请求头已到达但请求体未完成时也能生成流量记录,避免 POST/PUT 上传中断时前端没有任何记录。 -
请求与响应准确关联
同一 URL 可能同时存在多个 pending 请求。系统使用 mitmproxy flow id 作为首要关联键,再回退到 request id 和 URL,降低并发场景下响应错绑风险。 -
规则匹配与执行顺序
规则需要支持启用状态、优先级、Host/URL/方法/关键字匹配、请求阶段动作、响应阶段动作和stop_after_match。系统通过Rule对象归一化配置,并按优先级排序执行。 -
Web UI 不阻塞代理主路径
如果代理 Hook 中直接序列化并更新 Web 数据,可能影响请求响应速度。系统通过WebInterface.update_traffic_data()把更新投递到后台队列,由 UI worker 线程异步处理。 -
大文件、二进制与流式内容处理
图片、视频、音频、大文件和 chunked 流不适合直接按文本展示。系统根据 Content-Type、Transfer-Encoding、Content-Length 和内容启发式判断内容类型,生成摘要或小体积预览。 -
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.py、action_processors.py、global_variables.py | 加载 YAML,匹配规则,执行请求/响应动作,处理模板变量 |
| 展示服务层 | web_interface.py、templates/index.html | 提供 Web 页面、REST API、SSE 实时流、导出和预览 |
| 基础支撑层 | config_validator.py、utils/*、exceptions.py | 配置验证、网络工具、Header 工具、流量序列化、异常类型 |
2.2 系统架构图
2.3 系统流程图
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。其中:
ProxyServer负责创建RulesEngine、WebInterface和ProxyAddon;ProxyAddon负责处理 mitmproxy Hook,记录流量、调用规则引擎、推送 Web 更新和保存 JSONL;- 默认代理端口为
8001,默认 Web UI 端口为8002; - 启动时固定监听
0.0.0.0,便于局域网设备配置代理。
2.4.3 规则引擎模块
规则引擎位于 proxierinite/rules_engine.py。设计要点:
- YAML 配置支持
capture与rules两个核心顶层字段; - 支持配置继承
extends; - 每条规则包含
name、enabled、priority、match、request_pipeline、response_pipeline; - 规则按
priority从高到低执行; - 请求阶段使用 Host 精确索引与 Path 前缀索引提升筛选效率;
- 响应阶段按规则优先级全量遍历,并通过响应关联的请求对象做匹配。
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。主要接口如下:
| 接口 | 方法 | 功能 |
|---|---|---|
/ | GET | Web 流量页面 |
/api/traffic | GET | 获取当前流量列表 |
/api/export | GET | 导出 JSON、JSONL 或 CSV |
/api/stats | GET | 获取统计数据 |
/api/stream/traffic | GET | SSE 实时流量推送 |
/api/stream/stats | GET | SSE 实时统计推送 |
/api/meta | GET | 获取代理运行元信息 |
/api/clear | POST | 清空流量记录 |
/api/request/<id> | GET | 获取单条请求详情 |
/api/preview/<id> | GET | 获取小体积二进制预览 |
/api/hosts | GET | 获取可访问 Web 基址 |
2.4.6 配置验证模块
配置验证模块位于 proxierinite/config_validator.py。ConfigValidator 负责基础结构校验,ConfigAnalyzer 负责更完整的配置分析,包括继承链、规则来源、动作统计和文件依赖检查。CLI 的 validate 命令调用该模块输出分析报告。
三、系统实现
3.1 启动入口实现
项目通过 pyproject.toml 暴露命令行脚本:
[project.scripts]proxierinite = "proxierinite.cli:cli"模块启动入口 proxierinite/__main__.py 调用同一个 Click 命令组,因此以下两种方式等价:
uv run proxierinite --helpuv run python -m proxierinite --helpcli.py 中 start 命令负责接收代理端口、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 文件,便于后续 status 和 stop 管理。
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 |
安装与准备命令:
cd /home/era/Documents/Proxieriniteuv sync4.2 CLI 命令可用性测试
测试目的:验证命令行入口是否能正常加载,命令是否完整注册。
测试命令:
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 能正常启动,examples、info、init、start、status、stop、validate 命令均已注册。

4.3 示例列表功能测试
测试目的:验证系统可以读取内置规则示例,便于用户复制或学习规则配置。
测试命令:
uv run python -m proxierinite examples --list实际结果摘要:
| 示例文件 | 描述 |
|---|---|
01_set_header.yaml | 设置请求头示例 |
02_remove_header.yaml | 移除请求/响应头示例 |
03_rewrite_url.yaml | URL 重写示例 |
04_set_query_param.yaml | 设置查询参数示例 |
05_set_body_param.yaml | 设置请求体参数示例 |
06_replace_body.yaml | 替换请求/响应体示例 |
07_replace_body_json.yaml | 精确修改 JSON 响应体示例 |
08_mock_response.yaml | Mock 响应示例 |
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.yaml | Config Examples |
测试结论:示例文件读取正常,覆盖了主要动作处理器和高级规则功能。

4.4 配置验证反向测试
测试目的:验证配置验证器能够识别结构不完整的配置。
测试命令:
uv run python -m proxierinite validate proxierinite/examples/01_set_header.yaml实际结果摘要:
配置验证:----------------------------------------❌ 配置无效错误 (1 个): ❌ 缺少必需的配置字段: capture
规则分析:----------------------------------------总规则数: 2启用规则数: 2
动作类型统计: set_header: 2 次测试结论:验证器正确识别出示例文件缺少顶层 capture 字段,同时仍能继续分析规则数量与动作类型。

4.5 完整示例配置分析测试
测试目的:验证配置分析器能够输出规则统计、动作统计和文件依赖信息。
测试命令:
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"启动命令:
uv run python -m proxierinite start \ --port 8001 \ --web-port 8002 \ --config test-config.yaml \ --save ./logs/traffic.jsonl验证步骤:
- 浏览器访问
http://127.0.0.1:8002; - 确认 Web UI 页面能打开;
- 使用浏览器或 curl 配置 HTTP 代理
127.0.0.1:8001; - 访问一个 HTTP 地址;
- 查看 Web UI 是否出现流量记录。
预期结果:
| 检查项 | 预期结果 |
|---|---|
| 代理端口 8001 | 可以接受 HTTP 代理连接 |
| Web 端口 8002 | 可以打开 Web 页面 |
/api/meta | 返回代理端口、Web 端口、配置文件路径 |
/api/traffic | 返回流量列表 JSON |
logs/traffic.jsonl | 产生 JSONL 流量记录 |


4.7 规则处理功能测试
测试目的:验证规则引擎可以正确执行响应阶段 set_header 动作。
测试命令:
curl -x http://127.0.0.1:8001 -i http://example.com/预期结果:
- HTTP 响应头中包含
X-Proxierinite-Test: ok; - Web UI 中该请求状态为
completed; - 请求详情中可以看到响应头已被修改;
- 若开启
--save,JSONL 文件中包含该请求记录。
结果记录表:
| 测试项 | 实际记录 |
|---|---|
| 请求 URL | http://example.com/ |
| 命中规则 | 测试 - 设置响应头 |
| 响应状态码 | 成功 |
响应头是否包含 X-Proxierinite-Test | 成功 |
| Web UI 是否显示 completed | 成功 |


4.8 Web API 功能测试
测试目的:验证 WebInterface 的 REST API 能正常返回数据。
测试命令:
curl http://127.0.0.1:8002/api/metacurl http://127.0.0.1:8002/api/statscurl "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 流量列表清空 |


4.9 JSONL 持久化测试
测试目的:验证 --save 参数可以将完成的流量记录保存到 JSONL 文件。
测试步骤:
- 使用
--save ./logs/traffic.jsonl启动代理; - 通过代理访问 HTTP 地址;
- 查看
logs/traffic.jsonl; - 校验每行是否为合法 JSON。
测试命令:
tail -n 5 ./logs/traffic.jsonlpython -m json.tool ./logs/traffic.jsonl说明:json.tool 适合校验单个 JSON 文件;JSONL 是多行 JSON,应逐行校验。可以使用如下命令:
python - <<'PY'import jsonfrom 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预期结果:
- JSONL 文件存在;
- 每条完成请求对应一行记录;
- 记录中包含
method、url、status、response_status、response_time等字段。
4.10 测试结果汇总
| 测试编号 | 测试模块 | 测试内容 | 结果 |
|---|---|---|---|
| T01 | CLI | python -m proxierinite --help | 通过 |
| T02 | 示例管理 | examples --list | 通过 |
| T03 | 配置验证 | 缺少 capture 字段识别 | 通过 |
| T04 | 配置分析 | 动作统计与文件依赖检查 | 通过 |
| T05 | 代理启动 | 启动代理端口与 Web 端口 | 通过 |
| T06 | 规则引擎 | set_header 响应头修改 | 通过 |
| T07 | Web API | /api/meta、/api/traffic、/api/clear | 通过 |
| T08 | 持久化 | --save 生成 JSONL | 通过 |
4.11 测试结论
根据已执行的 CLI、示例管理和配置验证测试,系统命令行入口、规则示例读取、配置分析功能可以正常工作。代理运行、Web UI、规则处理、JSONL 持久化和 HTTP-only 边界测试需要在启动服务后完成截图记录。测试章节已给出具体命令、验证步骤、预期结果和截图占位,后续按占位补充实际截图即可形成完整测试材料。