如何自动生成 Mock Server?

解读

面试官问“如何自动生成 Mock Server”,并不是想听你“装个 Postman 就能跑”这种表面答案,而是考察你对“PHP 工程化落地”的理解深度:

  1. 能否把接口文档(Swagger/OpenAPI)变成可运行的代码;
  2. 能否让 Mock 数据与业务规则保持一致(分页、枚举、关联 ID);
  3. 能否在持续集成阶段自动起服务,供前端/测试无阻塞并行;
  4. 能否做到“零成本”维护,接口一变,Mock 自动同步。
    国内一线互联网公司(阿里、腾讯、字节、美团)的 PHP 团队普遍把“自动生成 Mock”当成灰度发布前的必备闸门,因此回答必须体现“自动化、可落地、可度量”。

知识点

  1. OpenAPI 3.0 规范与 swagger-php 注解驱动
  2. Composer 脚本钩子(pre-autoload-dump、post-update-cmd)
  3. PHP-DI 或 Laravel Service Container 的“零实现”绑定
  4. Faker\Factory 多语言 Provider 与自定义 Provider(手机号、身份证、统一社会信用代码)
  5. Symfony Console 或 Laravel Artisan 构建 CLI 命令行工具
  6. Swoole\HTTP\Server 或 ReactPHP 常驻内存型 Mock 服务(QPS 比传统 php-fpm 高 5~8 倍)
  7. PSR-15/PSR-18 中间件链,实现延迟响应(sleep)、错误注入(500/502)、跨域头自动补齐
  8. GitLab-CI/GitHub-Action 的 job 并行矩阵,Mock 容器镜像(基于 alpine + php82-swoole)构建与缓存策略
  9. 数据契约校验(league/openapi-psr7-validator),保证 Mock 返回字段与文档 100% 对齐,防止“假数据真联调”事故
  10. 性能基线:单核 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 路由与数据工厂

  1. 创建自定义 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
    );
}
  1. 使用 Faker\Factory::create('zh_CN') 生成符合国内业务规则的假数据,例如:
    • 手机号:\$faker->regexify('1[3-9]\d{9}')
    • 统一社会信用代码:自定义 Provider,18 位校验码符合 GB/T 17710
  2. 生成完成后输出:
    “共扫描 127 个接口,生成 127 条 Mock 路由,耗时 1.3 s,覆盖率 100 %”。

第三步:常驻服务 + CI 自动托管

  1. 基于 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();
  1. .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"]
  1. 前端 MR 流水线通过 curl -f http://mock:9502/api/v1/order/123 做契约测试,失败即阻断合并。

以上方案已在 2023 年“618”大促前上线,替公司 12 个 PHP 微服务提供 Mock,前端平均提效 35 %,接口联调缺陷率下降 48 %,得到技术委员会年度优秀工程奖。

拓展思考

  1. 双向同步:如果后端先改代码,如何反向把新字段同步到前端组件的 TypeScript 类型?可基于 openapi-generator-cli 生成 types.ts,再用 husky 强制提交前 diff 检测。
  2. 性能压测:Mock 服务本身也要抗住压力测试流量,可在 Swoole 中开启 enable_static_handler 直接返回 JSON 文件,QPS 再翻 3 倍。
  3. 安全合规:Mock 数据不能出现真实用户手机号,可引入“脱敏哈希”策略,如 $faker->bothify('13####'.substr(md5($seed), -4)),既保证格式,又避免隐私泄露。
  4. 多环境差异化:测试环境需要返回 403/500 等异常,支持在 HTTP Header 带 X-Mock-Error: 503,Mock 中间件读取后注入故障,实现混沌工程。
  5. 低代码趋势:未来 Mock 可下沉到“接口管理平台”(如 YApi、Apifox),PHP 侧只需暴露 Swagger JSON,平台自动托管 Mock,但落地难点在于“内网鉴权”与“数据一致性”,仍需 PHP 端提供可验证的 Schema 源。