1. 这不是一节普通的技术课它解决的是“学了不会用、用了不敢讲”的真实断层“第07讲集成、验证与面试题精讲”——光看标题你可能以为这只是某套课程里的常规一讲。但在我带过二十多期不同背景学员的实际教学中这一讲几乎总是成为整个学习路径的“分水岭时刻”。为什么因为前六讲讲的是单点能力怎么写一个接口、怎么配一个路由、怎么查一条数据而第07讲开始所有碎片被真正焊接到一起——你得把模块A的输出喂给模块B的输入让模块C在模块D失败时兜底再用一套可复现的逻辑去证明“它确实能跑通”最后还要在面试官面前用三分钟说清“为什么这里选Redis而不是本地缓存为什么验证要分三层而不是两层”。这不是知识叠加是能力跃迁。我见过太多人卡在这里代码在本地dev环境跑得飞起一上测试环境就报错单元测试全绿集成测试一半红简历写了“熟悉微服务”面试被问“你们服务间怎么验证数据一致性”当场卡壳。这些不是技术漏洞而是工程闭环意识的缺失。本讲的核心关键词——“集成”“验证”“面试题”——其实对应着软件交付链路上三个不可跳过的现实关卡系统能否连得上Integration→ 功能是否靠得住Verification→ 人能否讲得清Articulation。它不教新语法但教你如何把已知工具组合成可信系统它不堆新概念但逼你直面“理论上可行”和“实际上稳当”之间的巨大鸿沟。适合谁来细读这篇如果你正处在这样的阶段能独立完成小功能开发但参与联调时总被后端/前端/测试反复打回能写出基础测试用例但面对复杂交互场景不知从何下手验证或已经准备技术面试却总在“设计题”“故障排查题”“架构权衡题”上失分——那么这讲内容就是为你量身定制的“工程化补丁”。它不承诺速成但提供一套可拆解、可复用、可迁移的实战方法论。接下来我会完全基于真实项目节奏展开没有PPT式罗列只有我在某跨平台图像处理系统、某高校科研数据中台、某电商履约链路优化等三个典型场景中亲手踩坑、反复验证、最终沉淀下来的完整操作路径。2. 内容整体设计与思路拆解为什么必须把“集成-验证-面试”捆在一起讲2.1 传统教学的致命断层三件本该同步发生的事被硬生生切成三段多数技术课程的结构是线性的先学语言基础第1–3讲再学框架用法第4–5讲最后学“高级主题”第6讲之后。这种设计隐含一个危险假设开发者会自然地把学到的点状知识无缝拼合成端到端的交付能力。但现实是残酷的——我在某实验室协助搭建科研数据中台时一位博士生能用Python写出极其优雅的统计模型却在把模型接入Web API时卡了整整三天他反复检查Flask路由和参数解析却忽略了前端传来的JSON里有个字段名是user_id而模型函数签名要求的是userId。这个错误既不是语法问题也不是框架问题而是集成契约未对齐的典型表现。更隐蔽的问题在于“验证”的缺位。很多教程教“怎么写单元测试”但极少教“什么时候该写集成测试”。曾有学员兴奋地给我展示他100%覆盖的单元测试报告结果上线后支付回调接口因网络超时重试机制失效导致订单状态错乱。单元测试只验证了单个函数内部逻辑而集成测试要验证的是“当A服务调用B服务B服务返回超时响应A服务是否按预期降级并记录日志”。这两者目标完全不同测试策略、数据构造、断言方式也截然不同。把它们混为一谈等于用显微镜检查汽车发动机零件却忘了上路试驾。至于“面试题精讲”更常被当作应试技巧单独训练。但真实情况是高质量的面试题本质是对工程实践的抽象拷问。比如“如何设计一个秒杀系统”考的不是背诵RedisLua脚本而是你能否在脑中快速构建出“流量削峰→库存预减→异步落库→结果校验”的完整链路并预判每个环节的验证点如预减库存后如何验证用户下单请求没被重复提交异步落库失败如何保证最终一致性。如果平时做项目从不思考验证方案面试时必然抓瞎。所以本讲的设计逻辑非常明确以终为始倒推能力构建。我们不孤立讨论“集成怎么做”而是问“集成完成后你怎么证明它真的可靠”不空谈“验证是什么”而是问“验证通过的标准如何映射到面试官想听的技术判断力”不罗列面试题答案而是拆解“这道题背后实际考察的是哪一次线上事故的复盘经验”2.2 方案选型背后的硬核考量为什么聚焦“契约驱动”而非“代码驱动”市面上关于集成与验证的资料大多围绕具体工具展开Spring Cloud Alibaba怎么配Nacos、Postman怎么写测试脚本、Jest怎么mock依赖……这些很重要但属于“术”的层面。本讲选择“契约驱动”作为主线是因为它直击工程落地最痛的根源——协作成本。想象一个典型场景前端团队需要调用后端提供的用户信息接口。传统做法是后端写好接口发一份Swagger文档给前端前端按文档开发。问题在哪文档可能过期后端悄悄加了字段、理解可能偏差“status”字段文档写“0正常1禁用”前端却当成布尔值处理、验证可能脱节后端只测了200成功响应没测401未授权场景。结果就是联调第一天双方各执一词陷入“你文档没写清楚”“你代码没按文档实现”的扯皮。“契约驱动”的解法是在任何代码编写前先共同定义一份机器可读、双方共签的接口契约Contract。我们采用OpenAPI 3.0规范但关键不在格式而在流程第一步前后端坐在一起用白板画出核心交互流程图明确每个请求/响应的数据结构、状态码、错误码第二步将白板内容转化为OpenAPI YAML文件用openapi-generator自动生成Mock Server供前端联调和客户端SDK供后端调用第三步将契约文件纳入CI流水线每次PR提交时自动运行spectral进行规则校验如所有POST接口必须有400错误响应定义、所有字符串字段必须有maxLength约束。这个流程的价值远超工具本身。它强制双方在编码前就对齐业务语义把模糊的“应该怎样”变成精确的“必须怎样”。我在某电商履约项目中推行此方案后联调周期从平均5天缩短至1.5天因接口理解偏差导致的返工减少82%。更重要的是这份契约天然成为验证的黄金标准——测试用例不再凭经验编写而是直接从契约中生成每个200响应定义对应一个正向测试用例每个400定义对应一个边界值测试用例每个500定义对应一个异常流测试用例。提示契约不是文档是协议。它必须具备法律效力般的约束力——一旦签署任何一方修改都需对方确认并触发自动化测试回归。否则它只是另一份容易过期的PPT。2.3 面试题精讲的底层逻辑把“被提问”转化为“主动验证”很多人把面试题当作待解答的题目这是最大的认知误区。真正的高手把每道题视为一次微型项目复盘邀请。比如经典题“如果线上服务突然CPU飙升你怎么排查”表面看是考Linux命令实则考的是你日常是否建立了可观测性基线。一个合格的回答绝不是背诵top、jstack、arthas命令列表而是展现你的工程习惯“我们服务启动时会自动上报JVM内存池、GC次数、线程数到Prometheus所以我第一反应是看Grafana面板里这些指标是否同步异常”“如果指标无明显异常我会检查最近发布的变更——我们所有发布都强制关联Git Commit ID和部署时间戳所以能快速定位是否是某次配置变更引入了死循环”“最后才上服务器执行jstack因为我知道jstack本身会暂停JVM所以只在确认必要时才用”。看到区别了吗前者是“工具使用者”后者是“系统守护者”。本讲的“面试题精讲”核心就是帮你建立这种思维转换把每道题拆解为“我日常如何预防这个问题”“我遇到类似问题时验证路径是什么”“我的验证结论如何用数据支撑”——这才是面试官真正想听到的“技术深度”。3. 核心细节解析与实操要点从契约定义到验证落地的完整链条3.1 契约定义用OpenAPI 3.0写一份“能跑起来”的接口协议很多团队尝试契约先行却倒在第一步写的YAML文件根本跑不起来。问题往往出在“为了写而写”忽略了契约的两个核心属性可执行性能生成可用Mock和可验证性能驱动测试。下面以一个真实的用户登录接口为例详解关键细节。首先定义路径与方法paths: /api/v1/auth/login: post: summary: 用户登录 description: 使用手机号和密码登录返回JWT Token # 关键必须声明所有可能的HTTP状态码这是验证的起点 responses: 200: description: 登录成功 content: application/json: schema: $ref: #/components/schemas/LoginSuccessResponse 400: description: 请求参数错误如手机号格式不对 content: application/json: schema: $ref: #/components/schemas/ErrorResponse 401: description: 认证失败密码错误或账号禁用 content: application/json: schema: $ref: #/components/schemas/ErrorResponse 429: description: 请求过于频繁防暴力破解 content: application/json: schema: $ref: #/components/schemas/ErrorResponse重点来了responses部分不是摆设。我们用openapi-generator生成Mock Server时它会严格按此处定义的400/401/429状态码返回对应模拟响应。这意味着前端无需等待后端开发完成就能基于真实错误码调试错误提示UI。其次定义请求体requestBody必须包含可执行的示例examplesrequestBody: required: true content: application/json: schema: type: object properties: phone: type: string pattern: ^1[3-9]\\d{9}$ # 强制手机号正则避免前端传错 example: 13800138000 # 关键example必须符合pattern password: type: string minLength: 8 maxLength: 32 example: MyPass123! # 同样example必须满足约束 examples: # 这里定义多个典型场景供Mock Server使用 validLogin: summary: 正常登录请求 value: phone: 13800138000 password: MyPass123! invalidPhone: summary: 手机号格式错误 value: phone: 123 password: MyPass123!为什么examples如此重要因为openapi-generator生成的Mock Server会将examples中的validLogin、invalidPhone等作为预置请求模板。前端点击“发送”按钮时Mock Server会根据value中的数据结合responses定义自动返回对应的200或400响应。这比手写Mock脚本快十倍且零维护成本。最后定义响应Schema时必须区分“业务数据”与“元数据”components: schemas: LoginSuccessResponse: type: object properties: code: type: integer example: 0 # 统一成功码非HTTP状态码 message: type: string example: 登录成功 data: type: object properties: token: type: string example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... # JWT示例 expiresIn: type: integer example: 3600 # 令牌过期时间秒 required: [code, message, data]注意code/message是业务层统一返回结构与HTTP状态码分离。这样设计的好处是当HTTP返回200时业务层仍可通过code判断是“登录成功”还是“登录成功但需短信二次验证”code1001。这为后续的集成验证埋下伏笔——测试用例不仅要校验HTTP状态码还要校验业务code值。注意契约中所有example值必须经过人工校验其有效性。我曾见过团队因example中JWT示例过期导致前端Mock调试时一直收不到有效Token白白浪费半天。建议建立example校验清单手机号正则匹配、密码长度合规、JWT签名可解码等。3.2 集成验证三层验证体系覆盖从“能连上”到“能扛住”的全场景契约定义完代码开始编写。但“写完”不等于“集成完成”。我们采用经典的三层验证体系每层目标明确、工具固定、失败即阻断第一层连接性验证Connectivity Test——确保“能连上”目标验证服务间网络可达、基础认证通过、基础路由正确。 工具curljq轻量、无依赖、CI友好 实操示例验证用户服务是否能被订单服务调用# 1. 检查服务发现订单服务配置的用户服务地址是否能DNS解析 nslookup user-service.default.svc.cluster.local # 2. 检查基础连通绕过业务逻辑直连健康检查端点 curl -s -o /dev/null -w %{http_code} \ http://user-service:8080/actuator/health # 3. 检查基础认证用预置测试Token获取用户信息最小业务路径 TOKEN$(cat ./test-token.txt) curl -s -H Authorization: Bearer $TOKEN \ http://user-service:8080/api/v1/users/me | jq -r .code # 期望输出0表示基础链路畅通关键点此层验证必须在CI流水线的“构建后、部署前”阶段执行。它不关心业务逻辑只确认基础设施层无硬性阻断。若失败立即终止后续流程——避免把问题带到更复杂的集成测试环节。第二层契约符合性验证Contract Compliance Test——确保“没改错”目标验证实际运行的服务其真实响应是否100%符合OpenAPI契约定义。 工具dredd专为OpenAPI契约测试设计 配置文件dredd.yml关键项# 指向契约文件和实际服务地址 blueprint: ./openapi.yaml endpoint: http://user-service:8080 # 关键启用严格模式任何字段缺失或类型不符即失败 strict: true # 定义全局Header避免每个测试重复写 headers: Authorization: Bearer ${TEST_TOKEN}执行命令dredd --hookfiles./hooks.jshooks.js用于处理契约中无法静态定义的动态逻辑例如登录接口的password字段在契约中是明文示例但实际测试需用哈希值创建资源接口返回的id是UUID契约中只能写示例测试时需提取并用于后续查询。dredd的强大在于它会自动遍历契约中所有paths、所有responses、所有examples生成数百个测试用例。更重要的是它能检测“契约未定义但实际返回”的字段如后端悄悄加了debugInfo字段这正是防止“契约腐化”的关键防线。第三层业务流验证Business Flow Test——确保“能扛住”目标模拟真实用户行为验证跨服务业务流程的端到端正确性与稳定性。 工具Playwright浏览器级E2Ek6性能压测 实操案例电商下单全流程验证功能验证Playwright// 1. 前端登录调用Auth服务 await page.goto(https://shop.example.com/login); await page.fill(#phone, 13800138000); await page.fill(#password, MyPass123!); await page.click(#login-btn); // 2. 加购调用Cart服务 await page.goto(https://shop.example.com/product/123); await page.click(#add-to-cart); // 3. 下单调用Order服务触发User/Cart/Inventory服务联动 await page.goto(https://shop.example.com/cart); await page.click(#checkout); // 4. 断言订单创建成功且库存服务扣减正确 const orderNumber await page.textContent(.order-number); expect(orderNumber).toMatch(/^ORD-\d{8}$/); // 调用Inventory服务API验证库存 const inventoryRes await fetch(http://inventory-service:8080/api/v1/items/123/stock); expect((await inventoryRes.json()).available).toBe(99); // 从100减到99性能验证k6import http from k6/http; import { check, sleep } from k6; export const options { vus: 100, // 100个虚拟用户 duration: 30s, }; export default function () { // 模拟真实用户行为链路 const loginRes http.post(http://auth-service:8080/api/v1/auth/login, JSON.stringify({phone: 13800138000, password: MyPass123!})); check(loginRes, {logged in: (r) r.status 200}); const token loginRes.json().data.token; const orderRes http.post(http://order-service:8080/api/v1/orders, JSON.stringify({itemId: 123, quantity: 1}), { headers: { Authorization: Bearer ${token} } }); check(orderRes, {order created: (r) r.status 201}); sleep(1); }关键指标监控http_req_duration{p95}2000ms95%请求超2秒告警、http_req_failed0.1错误率超0.1%告警。这三层验证不是并列关系而是漏斗式过滤连接性验证筛掉基础设施问题契约验证筛掉接口不一致问题业务流验证最终确认业务价值交付。每一层失败都意味着不同层级的风险必须由不同角色介入运维、后端、全栈。3.3 面试题精讲三道高频题的“验证视角”拆解面试题的价值在于它暴露你日常工程实践的盲区。下面用三道真实高频题演示如何用“验证思维”重构回答。题1“如何保证分布式事务的一致性”常见错误答法罗列Seata、RocketMQ事务消息、TCC等名词解释原理。 验证视角答法 “在我负责的某高校科研数据中台项目中我们面临‘用户提交实验数据后需同时更新个人档案、生成分析报告、通知导师’的强一致性需求。我们没有一开始就选分布式事务框架而是先做了三件事验证业务容忍度和导师团队确认‘通知延迟5秒内可接受但档案和报告必须同时成功或同时失败’。这排除了最终一致性方案验证技术可行性用k6对MySQL XA事务压测发现并发超200TPS时prepare阶段锁表导致吞吐骤降40%。这否定了纯数据库XA验证方案成本对比Seata AT模式与TCC模式。AT模式侵入性低但需改造所有SQLTCC需编写大量补偿逻辑。我们选择AT并用契约验证在OpenAPI中明确定义‘提交数据’接口的200响应代表‘所有子事务已提交’409代表‘冲突需重试’500代表‘事务协调器故障’。所有测试用例必须覆盖这三种状态。”核心转变从“背原理”到“讲决策依据”而依据全部来自日常验证实践。题2“Redis和MySQL数据不一致怎么办”常见错误答法讲双写、删除缓存、延时双删等策略。 验证视角答法 “我们采用‘更新DB后删除缓存’策略但重点不在策略本身而在如何验证它真的有效。我们建立了三重验证实时验证在删除缓存操作后立即用redis-cli检查key是否存在失败则告警并触发重试离线验证每天凌晨用Spark作业扫描MySQL主表和Redis缓存对10万条数据抽样比对生成不一致报告混沌验证在测试环境定期注入网络分区故障用Chaos Mesh观察缓存删除失败时降级逻辑如读DB是否被正确触发并记录降级成功率。 去年一次线上事故中正是离线验证报告提前2天发现了某类冷门数据的缓存更新遗漏避免了更大范围影响。”关键点面试官想听的不是“你知道什么”而是“你如何确保你知道的在生产环境里真的管用”。题3“如果让你设计一个短链接服务你会怎么做”常见错误答法从哈希算法、存储选型、高并发架构一路讲到CDN。 验证视角答法 “我会先定义它的核心验证目标再反推设计可用性验证要求99.99%可用。这意味着单点故障必须消除。所以存储层必须是多AZ Redis集群且读写分离短链跳转必须支持降级如Redis不可用时直接查MySQL正确性验证要求100%跳转准确。所以所有写入操作必须有幂等性校验用SETNX唯一ID且每次跳转必须记录原始长链与短链的映射日志供审计性能验证要求P99延迟50ms。所以我们用wrk压测发现单Redis实例在QPS5000时延迟飙升于是引入本地Caffeine缓存热点短链并用契约定义‘/s/{code}’接口的200响应头必须包含X-Cache: HIT/MISS方便监控缓存命中率。 最后所有这些验证点都会转化为OpenAPI契约中的responses和x-extension字段成为自动化测试的输入。”本质设计题的答案就是一份详尽的验证方案说明书。4. 实操过程与核心环节实现从零搭建一个可验证的微服务Demo4.1 环境准备与工具链初始化5分钟搞定可复现环境所有操作均在Ubuntu 22.04 LTS环境下验证全程使用Docker Compose管理依赖确保环境100%可复现。无需安装Java/Node.js等运行时所有服务以容器形式运行。第一步初始化项目骨架mkdir verified-microservice-demo cd verified-microservice-demo # 创建核心目录结构 mkdir -p auth-service openapi contracts tests # 初始化Docker Compose管理所有服务 cat docker-compose.yml EOF version: 3.8 services: # Auth服务提供JWT认证 auth-service: image: ghcr.io/verified-demo/auth-service:latest ports: [8080:8080] environment: - SPRING_PROFILES_ACTIVEdocker depends_on: [redis] # User服务提供用户信息 user-service: image: ghcr.io/verified-demo/user-service:latest ports: [8081:8081] environment: - SPRING_PROFILES_ACTIVEdocker depends_on: [auth-service, redis] # Redis共享缓存与会话存储 redis: image: redis:7-alpine command: redis-server --appendonly yes ports: [6379:6379] # Mock Server基于契约的前端联调服务 mock-server: image: stoplight/prism:4 ports: [4010:4010] volumes: [./openapi:/tmp/openapi] command: mock -h 0.0.0.0:4010 /tmp/openapi/openapi.yaml # 测试执行器运行所有验证脚本 test-runner: image: cypress/included:12.17.3 volumes: [./tests:/e2e/tests, ./openapi:/e2e/openapi] environment: - CYPRESS_BASE_URLhttp://host.docker.internal:4010 depends_on: [mock-server] EOF关键设计说明ghcr.io/verified-demo/*是预构建的轻量级服务镜像基于Spring Boot 3.x已内置健康检查端点和基础API避免学员陷入环境配置泥潭host.docker.internal是Docker Desktop的特殊DNS确保容器内能访问宿主机启动的Mock Server所有服务通过depends_on声明依赖Compose会按序启动避免“服务未就绪就调用”的经典问题。第二步生成并验证初始契约# 创建OpenAPI契约文件 cat openapi/openapi.yaml EOF openapi: 3.0.3 info: title: Verified Microservice Demo API version: 0.1.0 paths: /health: get: summary: 服务健康检查 responses: 200: description: 服务健康 content: application/json: schema: type: object properties: status: type: string example: UP components: schemas: {} EOF # 启动Mock Server验证契约语法 docker-compose up -d mock-server curl -s http://localhost:4010/health | jq .status # 应输出UP证明契约可执行此时你已拥有一个可工作的Mock Server前端可立即开始联调无需等待后端开发。4.2 集成验证全流程实操从连接性到业务流的逐层通关现在我们启动所有服务执行完整的三层验证。所有命令均在项目根目录执行。连接性验证Connectivity Test# 启动全部服务 docker-compose up -d # 等待服务就绪简单轮询 for i in {1..30}; do if curl -s http://localhost:8080/actuator/health | grep -q status:UP; then echo ✅ Auth service is UP break fi sleep 2 done # 执行连接性验证脚本 cat tests/connectivity.sh EOF #!/bin/bash set -e echo Testing connectivity... # 1. DNS解析 if nslookup auth-service 2/dev/null | grep -q Address:; then echo ✅ DNS resolution OK else echo ❌ DNS resolution failed exit 1 fi # 2. 健康检查 if curl -s -o /dev/null -w %{http_code} http://localhost:8080/actuator/health | grep -q 200; then echo ✅ Health check OK else echo ❌ Health check failed exit 1 fi # 3. 基础API调用使用预置测试Token TOKENeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c if curl -s -H Authorization: Bearer $TOKEN http://localhost:8080/api/v1/auth/validate | jq -r .code 2/dev/null | grep -q 0; then echo ✅ Basic API call OK else echo ❌ Basic API call failed exit 1 fi echo Connectivity test passed! EOF chmod x tests/connectivity.sh ./tests/connectivity.sh执行结果应显示 Connectivity test passed!。若失败请检查docker-compose logs auth-service查看启动日志。契约符合性验证Contract Compliance Test# 安装Dredd全局 npm install -g dredd # 创建Dredd配置 cat dredd.yml EOF blueprint: ./openapi/openapi.yaml endpoint: http://localhost:8080 header: [Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c] language: nodejs hookfiles: ./tests/hooks.js EOF # 创建Hooks处理动态逻辑 cat tests/hooks.js EOF const hooks require(hooks); // 在登录测试前生成一个随机手机号 hooks.before(Auth Login Login with valid credentials, (transaction) { const phone 138 Math.floor(Math.random() * 1000000000).toString().padStart(8, 0); transaction.request.body JSON.stringify({ phone: phone, password: MyPass123! }); }); // 在登录后提取Token用于后续请求 hooks.after(Auth Login Login with valid credentials, (transaction) { const body JSON.parse(transaction.real.body); const token body.data.token; // 将token注入到后续所有请求的Authorization头中 hooks.setGlobalVariable(AUTH_TOKEN, token); }); EOF # 执行契约验证 dredd --dry-run # 先干运行检查配置 dredd --no-color # 正式运行输出详细结果Dredd会自动执行契约中定义的所有测试用例。成功时你会看到类似passing: 12/12的输出。若失败Dredd会精确指出哪个example、哪个response、哪个字段不匹配这是传统手工测试无法比拟的精准度。业务流验证Business Flow Test# 创建Playwright测试 mkdir -p tests/e2e cat tests/e2e/login.spec.js EOF const { test, expect } require(playwright/test); test(Login flow end-to-end, async ({ page }) { // 1. 访问Mock Server提供的登录页 await page.goto(http://localhost:4010/login.html); // 2. 输入测试凭证使用契约中定义的validLogin example await page.fill(#phone, 13800138000); await page.fill(#password, MyPass123!); await page.click(#login-btn); // 3. 验证登录成功Mock Server会返回200 JWT await expect(page.locator(.welcome-message)).toHaveText(欢迎回来13800138000); // 4. 调用User服务API验证Token有效性跨服务调用 const response await page.request.get(http://localhost:8081/api/v1/users/me, { headers: { Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c } }); expect(response.status()).toBe(200); const userData await response.json(); expect(userData.code).toBe(0); expect(userData.data.phone).toBe(13800138000); }); EOF # 运行E2E测试 npx playwright test --projectchromiumPlaywright会自动打开浏览器执行登录操作并验证跨服务调用结果。成功时控制台显示1 passed。这证明前端、Auth服务、User服务已形成可信闭环。