Files
shz-backend/docs/app-interview-rtc-api.md
2026-07-31 22:48:45 +08:00

224 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 面试视频 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=<url-encoded-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` 是否完全一致。