# 面试视频 Token 接口 ## 1. 接口用途 面试官和候选人分别调用同一个 Token 接口,但每次请求只返回当前调用者自己的连接凭据: ```text 企业端调用一次 → 面试官 peerId + token 候选人端调用一次 → 候选人 peerId + token ``` 企业端不会拿到候选人的 token,候选人端也不会拿到面试官的 token。 两次请求必须关联到同一条面试邀约记录,后端会为同一个 `interviewId` 复用同一个 `roomId`,并为每次调用生成新的 `peerId` 和一次性 token。 ## 2. 面试官获取 Token 企业端使用后台用户登录态调用: ```http POST /cms/interview/rtc/token?interviewId=123 Authorization: Bearer <企业端登录Token> Content-Type: application/json ``` 请求体为空: ```json {} ``` 企业端接口只返回当前面试官的一套凭据。 ## 3. 候选人获取 Token 候选人端使用移动端登录态调用: ```http POST /app/interview/rtc/token?interviewId=123 Authorization: Bearer <候选人登录Token> Content-Type: application/json ``` 请求体为空: ```json {} ``` 候选人端接口只返回当前候选人的一套凭据。 ## 4. 成功响应 两个接口的返回格式相同,但每次只对应当前调用者: ```json { "code": 200, "msg": "操作成功", "data": { "roomId": "room-0a4c3fbd8f9e4b70a0e2de99f6b5f2a8", "peerId": "peer-4a78d8f0c4a5468fb0d8d05a8199b3bb", "token": "eyJhbGciOiJIUzI1NiJ9...", "expiresIn": "5m" } } ``` 字段说明: | 字段 | 类型 | 说明 | | --- | --- | --- | | `code` | number | `200` 表示成功 | | `msg` | string | 接口提示信息 | | `data.roomId` | string | 当前面试房间 ID;同一个 `interviewId` 的双方得到相同值 | | `data.peerId` | string | 当前调用者在房间内的唯一 ID | | `data.token` | string | 当前调用者的一次性 MyRTC JWT | | `data.expiresIn` | string | token 有效期,当前通常为 `5m` | ## 5. 调用流程 假设面试邀约 ID 为 `123`。 ### 5.1 企业端 ```javascript const response = await request.post( '/cms/interview/rtc/token?interviewId=123', {} ) if (response.code !== 200) { throw new Error(response.msg || '获取面试官视频凭据失败') } const rtc = response.data await rtcClient.connect({ roomId: rtc.roomId, peerId: rtc.peerId, token: rtc.token }) ``` ### 5.2 候选人端 ```javascript const response = await request.post( '/app/interview/rtc/token?interviewId=123', {} ) if (response.code !== 200) { throw new Error(response.msg || '获取候选人视频凭据失败') } const rtc = response.data await rtcClient.connect({ roomId: rtc.roomId, peerId: rtc.peerId, token: rtc.token }) ``` 两端的 `roomId` 必须相同,但两端的 `peerId` 和 `token` 必须使用各自接口返回的值,不能互换。 ## 6. MyRTC WebSocket 连接 当前 MyRTC 服务的信令地址是: ```text wss://rtc.zhaopinzao8dian.com/signaling?token= ``` 原生 WebSocket 建议使用 `URL` 自动编码 token: ```javascript const wsUrl = new URL('wss://rtc.zhaopinzao8dian.com/signaling') wsUrl.searchParams.set('token', rtc.token) const ws = new WebSocket(wsUrl.toString()) ``` 连接成功后发送 `join` 请求: ```json { "type": "request", "id": 1, "action": "join", "payload": { "roomId": "room-0a4c3fbd8f9e4b70a0e2de99f6b3bb", "peerId": "peer-4a78d8f0c4a5468fb0d8d05a8199b3bb" } } ``` `id` 必须是正整数。当前 MyRTC 服务要求使用 `id`,不是 `requestId`。 ## 7. interviewId 的来源 `interviewId` 就是业务表 `interview_invitation` 的主键 ID,不是 MyRTC 临时生成的 ID。 候选人端可以从以下接口获得面试邀约 ID: ```http GET /app/interview/list GET /app/interview/{id} ``` 返回数据中的: ```json { "id": 123 } ``` 其中 `id` 就是获取 RTC Token 时使用的 `interviewId`。 企业端也应使用企业端面试列表中的同一条面试邀约记录 ID。 ## 8. Token 注意事项 - token 是一次性的,成功 `join` 后即被 MyRTC 消费; - token 默认有效期为 `5m`; - 页面刷新或连接断开后重新连接,需要重新获取 token; - 每次获取 token 都会生成新的 `peerId`; - 同一个 `interviewId` 在 Redis 中对应同一个 `roomId`,有效期默认 6 小时; - 前端不需要调用房间详情查询和房间销毁接口; - 前端不需要保存或传递 MyRTC 的 `ADMIN_TOKEN`。 ## 9. 错误响应 ### 未登录 ```json { "code": 500, "msg": "未登录" } ``` ### 缺少 interviewId ```json { "code": 400, "msg": "Required request parameter 'interviewId' for method parameter type Long is not present" } ``` ### MyRTC JWT 密钥未配置 ```json { "code": 500, "msg": "MyRTC JWT_SECRET 未配置" } ``` 如果后端签发 token 使用的密钥和 MyRTC 服务配置不一致,WebSocket 握手会失败,需要检查业务后端和 MyRTC 的 `JWT_SECRET` 是否完全一致。