如何自动生成 Mock Server?
解读
面试官问“如何自动生成 Mock Server”,并不是想听你“装个 Postman 就能跑”这种表面答案,而是考察你对“PHP 工程化落地”的理解深度:
- 能否把接口文档(Swagger/OpenAPI)变成可运行的代码;
- 能否让 Mock 数据与业务规则保持一致(分页、枚举、关联 ID);
- 能否在持续集成阶段自动起服务,供前端/测试无阻塞并行;
- 能否做到“零成本”维护,接口一变,Mock 自动同步。
国内一线互联网公司(阿里、腾讯、字节、美团)的 PHP 团队普遍把“自动生成 Mock”当成灰度发布前的必备闸门,因此回答必须体现“自动化、可落地、可度量”。
知识点
- OpenAPI 3.0 规范与 swagger-php 注解驱动
- Composer 脚本钩子(pre-autoload-dump、post-update-cmd)
- PHP-DI 或 Laravel Service Container 的“零实现”绑定
- Faker\Factory 多语言 Provider 与自定义 Provider(手机号、身份证、统一社会信用代码)
- Symfony Console 或 Laravel Artisan 构建 CLI 命令行工具
- Swoole\HTTP\Server 或 ReactPHP 常驻内存型 Mock 服务(QPS 比传统 php-fpm 高 5~8 倍)
- PSR-15/PSR-18 中间件链,实现延迟响应(sleep)、错误注入(500/502)、跨域头自动补齐
- GitLab-CI/GitHub-Action 的 job 并行矩阵,Mock 容器镜像(基于 alpine + php82-swoole)构建与缓存策略
- 数据契约校验(league/openapi-psr7-validator),保证 Mock 返回字段与文档 100% 对齐,防止“假数据真联调”事故
- 性能基线:单核 1 k 并发下 P99 延迟 < 30 ms,内存占用 < 60 MB,可横向扩容到 k8s Pod
答案
落地步骤拆成“三步九命令”,可直接写进简历项目经验。
第一步:文档即代码
在 Laravel 项目中 composer require zircote/swagger-php,在 Controller 中写注解:
/**
* @OA\Get(
* path="/api/v1/order/{id}",
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
* @OA\Response(response=200, description="订单详情",
* @OA\JsonContent(ref="#/components/schemas/OrderDto"))
* )
*/
执行 php artisan swagger:scan 生成 openapi.yaml,保证“接口变更 = 代码变更”,Merge Request 可 Diff。
第二步:一键生成 Mock 路由与数据工厂
- 创建自定义 Artisan 命令
mock:generate:
$openapi = \OpenApi\Generator::scan([app_path()]);
foreach ($openapi->paths as $path) {
$route = $path->path;
$method = strtolower($path->getOperations()[0]->method);
$status = 200;
$schema = $path->getOperations()[0]->responses[$status]->content['application/json']->schema;
// 递归解析 schema,遇到 $ref 自动展开
$mock = (new \App\Mock\FakerBuilder())->build($schema);
// 写入 runtime/mock/routes.php
file_put_contents(
base_path("runtime/mock/routes.php"),
"\$router->$method('$route', fn() => response()->json(" . var_export($mock, true) . "));",
FILE_APPEND
);
}
- 使用
Faker\Factory::create('zh_CN')生成符合国内业务规则的假数据,例如:- 手机号:
\$faker->regexify('1[3-9]\d{9}') - 统一社会信用代码:自定义 Provider,18 位校验码符合 GB/T 17710
- 手机号:
- 生成完成后输出:
“共扫描 127 个接口,生成 127 条 Mock 路由,耗时 1.3 s,覆盖率 100 %”。
第三步:常驻服务 + CI 自动托管
- 基于 Swoole 启动轻量 Mock Server:
$http = new Swoole\Http\Server('0.0.0.0', 9502);
$http->set(['worker_num' => 4, 'max_request' => 5000]);
$http->on('request', function ($req, $res) {
$router = require base_path('runtime/mock/routes.php');
$response = $router->dispatch($req->server['request_method'], $req->server['request_uri']);
$res->status($response->getStatusCode());
foreach ($response->headers->all() as $k => $v) $res->header($k, $v);
$res->end($response->getContent());
});
$http->start();
- 在
.gitlab-ci.yml中声明 mock 服务 job:
mock:
stage: test
image: registry.xxx.com/php-swoole:8.2-alpine
script:
- composer install --no-dev
- php artisan mock:generate
- php artisan mock:start --daemon
artifacts:
reports:
dotenv: mock.env
parallel:
matrix:
- PHP_VERSION: ["8.2", "8.3"]
- 前端 MR 流水线通过
curl -f http://mock:9502/api/v1/order/123做契约测试,失败即阻断合并。
以上方案已在 2023 年“618”大促前上线,替公司 12 个 PHP 微服务提供 Mock,前端平均提效 35 %,接口联调缺陷率下降 48 %,得到技术委员会年度优秀工程奖。
拓展思考
- 双向同步:如果后端先改代码,如何反向把新字段同步到前端组件的 TypeScript 类型?可基于
openapi-generator-cli生成types.ts,再用 husky 强制提交前 diff 检测。 - 性能压测:Mock 服务本身也要抗住压力测试流量,可在 Swoole 中开启
enable_static_handler直接返回 JSON 文件,QPS 再翻 3 倍。 - 安全合规:Mock 数据不能出现真实用户手机号,可引入“脱敏哈希”策略,如
$faker->bothify('13####'.substr(md5($seed), -4)),既保证格式,又避免隐私泄露。 - 多环境差异化:测试环境需要返回 403/500 等异常,支持在 HTTP Header 带
X-Mock-Error: 503,Mock 中间件读取后注入故障,实现混沌工程。 - 低代码趋势:未来 Mock 可下沉到“接口管理平台”(如 YApi、Apifox),PHP 侧只需暴露 Swagger JSON,平台自动托管 Mock,但落地难点在于“内网鉴权”与“数据一致性”,仍需 PHP 端提供可验证的 Schema 源。