8.0 KiB
后端联调 · 前端实现说明
适用范围:
有职(youzhi)App 前端对接《职来后端接口联调说明》(job.youthome.com.cn规范) 关联文件:src/api/http.ts、src/api/auth.ts、src/lib/token-store.ts、src/context/AuthContext.tsx、src/types/user.ts本文只记录前端已落地的地基与契约映射,完整接口字段以运行时 OpenAPI 为唯一依据(规范 §7)。
一、本次已落地(地基,不涉及业务端点)
| 层 | 文件 | 内容 |
|---|---|---|
| 请求层 | src/api/http.ts |
统一出口:Base URL + Bearer 注入 + 信封解析 + 401 单飞刷新 + X-Request-Id + 状态码语义 |
| 令牌 | src/lib/token-store.ts |
accessToken + refreshToken 内存单例 + AsyncStorage 持久化 |
| 鉴权 | src/api/auth.ts |
sendSmsCode / loginByPassword / loginBySms / fetchCurrentUser / requestLogout / registerCompany |
| 会话 | src/context/AuthContext.tsx |
setSession(access,refresh,expiresAt);启动时 hydrateTokens;注册 401 清会话回调 |
| 角色 | src/types/user.ts + auth.ts |
AppRole 扩 admin;mapBackendRole(STUDENT→candidate / COMPANY→enterprise / ADMIN→admin) |
| 环境 | app.config.js |
默认 apiBaseUrl = https://job.youthome.com.cn/api/v1(保留 API_BASE_URL 环境变量覆盖) |
| mock 开关 | app.config.js + http.ts |
extra.apiUseMock(默认 true);isMockMode() 决定业务函数走 mock 还是真实请求;联调期置 false |
业务端点按 mock 开关 分阶段落地:开发期(apiUseMock=true)返回本地数据不触网,联调期(false)直连后端。jobs / profile / messages 等 100+ mock 函数逐个替换为真实 request() 调用,页面与 hook 零改动。
二、规范条款逐条对照
| 规范 | 前端现状 |
|---|---|
| §1 基地址 / 健康检查 / OpenAPI | 基地址已接 API_BASE_URL;checkHealth() 已实现对 /health(UP 判定);OpenAPI 为后端准绳,前端不手抄 |
§3 信封 code/message/data/requestId/timestamp |
request() 解析 envelope;code!==200 抛 ApiError;后端 message 优先(更具体),无 message 时回退状态码文案 |
§3 Authorization: Bearer |
自动注入;匿名接口(登录/短信/刷新)显式 auth:false 不带头 |
§4 双 Token + /auth/refresh |
token-store 持久化 access+refresh;401 触发刷新 |
| §4 一次串行刷新 + 重放 | 模块级 refreshPromise 单飞闸门:并发 401 只刷一次,成功后重放原请求 |
| §4 刷新失败清会话 | 清 Token + unauthorizedHandler(AuthContext 注册为清登录态) |
| §4 Token 不打印/上报/进 URL | 令牌仅在 http.ts 内层使用,错误对象不回吐原始 Token |
§5 角色以后端 /auth/me 为准 |
fetchCurrentUser() 返回映射后角色;密码登录页(P2PasswordLogin)登录后调 /auth/me 并 setRole,与本地选择不一致时纠正路由 |
| §6 企业注册 | registerCompany() 已实现对 /auth/company/register;客户端不提交 userId/role/verified/passwordHash |
| §8 状态码语义 | pickHttpMessage 覆盖 400/401/403/404/409/429/500/503;网络异常降级为 httpStatus=0 |
| §10 安全 | 不写 Token/验证码/密码到日志或前端 DOM;X-Request-Id 用于联调报障 |
三、业务端点转换进度(mock 开关 + 全量 fetch 函数,2026-09-24 收口)
转换规则:保留函数签名与返回类型
T(即 AGENTS.md「保留签名、只换函数体」),if (isMockMode())分支保留本地数据,真实分支走request<T>(path, { auth, query })。路径按规范 §7 重映射(旧@url多带/api前缀、未带/v1,已校正)。
3.1 已落地真实端点(2026-09-28 经 OpenAPI 校正)
路径以
docs/联调路径校正映射.md为权威逐函数表;下表仅列本次确认可直连的端点(ALIGNED + WRONG→REAL)。
| 函数 | 真实路径 | 鉴权 | 说明 |
|---|---|---|---|
fetchJobList |
GET /jobs |
否 | 分页信封 {items} |
fetchJobDetail |
GET /jobs/{id} |
否 | 公开岗位详情 |
fetchJobPreference |
GET /profile/me/preferences |
是 | 原 /profile/me/job-preference 已校正 |
fetchFavorites |
GET /jobs/favorites |
是 | 原 /profile/me/favorites 已校正 |
fetchJobProgress |
GET /profile/me/career-progress |
否 | 原 /tools/job-progress 已校正 |
fetchEmployeeReviews |
GET /jobs/{id}/reviews |
否 | |
createJobReview |
POST /jobs/{id}/reviews |
是 | body {content} |
fetchCompareData |
GET /jobs/compare |
否 | |
fetchUserProfile |
GET /profile/me |
是 | |
fetchResume |
GET /profile/me/resume |
是 | 原 /resume 已校正(修复双前缀 bug) |
fetchConversations |
GET /conversations |
是 | 原 /messages/conversations 已校正 |
fetchNotifications |
GET /notifications |
是 | 原 /messages/notifications 已校正 |
fetchInterviews |
GET /interviews/me |
是 | 原 /messages/interviews 已校正 |
fetchConversation |
GET /conversations/{id} |
是 | 原 /chat/conversations/{id} 已校正 |
fetchRankData |
GET /jobs/{jobId}/competition-ranking |
否 | 原 /jobs/rank 已校正(修复 ${jobId} 未插值 bug) |
fetchCandidateDetail |
GET /company/candidates/{applicationId} |
是 | 原 /enterprise/candidates 已校正 |
fetchInterviewScore |
GET /interviews/{id}/score |
是 | 原 /enterprise/interviews 已校正 |
fetchInterviewScoreDraft |
PUT /interviews/{id}/score |
是 | 草稿复用评分端点,原 /enterprise/.../draft 已校正 |
fetchOfferCompareData |
GET /offers/compare |
否 | 已对齐 |
写函数
saveJobPreference(PUT /profile/me/preferences)已校正路径;其余saveResume*/saveWeightSettings/saveSalaryRecord等经审计属「幽灵域」(后端无 OpenAPI 契约),已退回 mock-only。
3.1.2 幽灵域(本轮批量转换的其余 62 个 fetch 函数,2026-09-28 校正)
经 OpenAPI 审计,这 62 个函数所属域(/growth、/user、/tools、/game、/interview、/evaluation、/enterprise、/legal、/settings、/salary、/operation 等)后端均无契约。处理方式:保留
if(isMockMode())mock 分支,真实态不再调用request()(翻真实开关也不触网),待后端补齐契约后再接。原占位【待确认】标记已全部清除。逐函数明细见docs/联调路径校正映射.md§三。
3.2 待转 / 明确不接后端
- 设备本地能力(保持 mock,无后端等价物):
fetchCacheSize(存储占用)、fetchCarrierPhone(运营商取号 SDK)、fetchWechatLoginResult(微信登录态)、fetchOnboardingProfile(本地引导资料唯一真相源)、fetchOnboardingChecklist(本地清单派生)、fetchDeleteAllData(本地清空)。 - 非 fetch 写函数(不在本次 fetch 范围,后续接):
sendChatMessage、saveResume*系列、saveOnboardingProfile、toggleFavorite、saveJobPreference等写操作——需 PUT/POST body 映射 + 保留本地 storage 回退作为真实后端未就绪时的兜底。
四、明确未做(写入类 + 实时能力,下一阶段)
- WebSocket:
wss://job.youthome.com.cn/api/v1/ws未接入(无对应实时功能)。 - 企业入驻状态机:
/companies/me/onboarding的missingFields/allowedActions驱动 UI 尚未接。 - 其余入口页角色纠正:仅密码登录页已接
/auth/me;微信登录、验证码登录等入口需在登录后补齐角色权威化。 - 写入类函数:见 §3.2 非 fetch 写函数(sendChatMessage / saveResume* / saveOnboardingProfile / toggleFavorite / saveJobPreference 等),需补 body 映射与本地 storage 兜底。
五、命名待确认(非阻塞)
- 域名
youthome.com.cn(青年家)与 App 品牌「有职 / youzhi」不一致;Storage 前缀仍为历史遗留qingsongpin:,勿擅自改名(会导致老用户本地态失效)。