Files
shz-backend/docs/app-interview-rtc-api.md

224 lines
4.9 KiB
Markdown
Raw Normal View History

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