7.7 KiB
7.7 KiB
API 路径配置说明
📋 概述
本项目使用统一的 API 路径配置机制,通过环境变量和辅助函数确保开发环境和生产环境的 API 调用一致性。
🔧 配置方式
1. 环境变量配置
开发环境 (.env)
REACT_APP_API_BASE_URL=http://localhost:5001
生产环境 (.env.production)
REACT_APP_API_BASE_URL=https://d1kt.cn/api
2. 代码中的使用
所有 API 调用统一使用 api 对象(来自 src/api/apiClient.ts):
import { api } from './api/apiClient';
// ✅ 正确用法
const users = await api.get<User[]>('/admin/users');
// ❌ 不要直接使用 apiClient
// const response = await apiClient.get('/admin/users');
🌐 URL 构造流程
开发环境
1. 代码调用:api.get('/admin/users')
↓
2. getFullApiPath('/admin/users')
→ '/api/admin/users'
↓
3. axios.get(API_BASE_URL + '/api/admin/users')
→ axios.get('http://localhost:5001/api/admin/users')
↓
4. 最终请求:http://localhost:5001/api/admin/users
↓
5. 后端接收:/api/admin/users ✅
生产环境
1. 代码调用:api.get('/admin/users')
↓
2. getFullApiPath('/admin/users')
→ '/api/admin/users'
↓
3. axios.get(API_BASE_URL + '/api/admin/users')
→ axios.get('https://d1kt.cn/api/api/admin/users')
↓
4. 浏览器请求:https://d1kt.cn/api/api/admin/users
↓
5. Nginx 处理:
location /api/ {
proxy_pass http://localhost:5001/;
}
→ 去掉第一个 /api,转发到后端
↓
6. 后端接收:http://localhost:5001/api/admin/users ✅
📊 关键点说明
✅ 为什么生产环境需要两个 /api?
-
第一个
/api:Nginx 反向代理的路径匹配location /api/ { proxy_pass http://localhost:5001/; }- 浏览器请求
https://d1kt.cn/api/xxx - Nginx 匹配到
/api/后,去掉这部分,转发到后端 - 后端收到
http://localhost:5001/xxx
- 浏览器请求
-
第二个
/api:后端路由的前缀- 后端所有路由都以
/api开头 - 例如:
app.use('/api/admin', adminRoutes) - 所以需要请求
/api/admin/users
- 后端所有路由都以
-
组合结果:
浏览器 → https://d1kt.cn/api/api/admin/users Nginx → 转发 http://localhost:5001/api/admin/users 后端 → 路由匹配 /api/admin/users ✅
🔍 统一的调用方式
所有页面都使用相同的逻辑
| 功能模块 | API 调用示例 | 最终 URL(开发) | 最终 URL(生产) |
|---|---|---|---|
| 打字练习 | api.get('/practice-records/statistics') |
http://localhost:5001/api/practice-records/statistics |
https://d1kt.cn/api/api/practice-records/statistics |
| 用户管理 | api.get('/admin/users') |
http://localhost:5001/api/admin/users |
https://d1kt.cn/api/api/admin/users |
| 词汇学习 | api.get('/vocabulary/word-sets') |
http://localhost:5001/api/vocabulary/word-sets |
https://d1kt.cn/api/api/vocabulary/word-sets |
| 扫雷游戏 | api.get('/minesweeper/leaderboard/beginner') |
http://localhost:5001/api/minesweeper/leaderboard/beginner |
https://d1kt.cn/api/api/minesweeper/leaderboard/beginner |
🚀 部署步骤
生产环境部署
-
在服务器上创建
.env.production文件cd /path/to/typing_practiceweb cp .env.production.example .env.production nano .env.production -
配置生产环境变量
REACT_APP_API_BASE_URL=https://d1kt.cn/api -
构建前端
npm run build这会自动读取
.env.production文件 -
确认 Nginx 配置
location /api/ { proxy_pass http://localhost:5001/; } -
重启服务
sudo nginx -s reload pm2 restart typing-backend
⚠️ 常见错误
❌ 错误配置示例
# ❌ 生产环境配置为空字符串
REACT_APP_API_BASE_URL=
# 结果:请求变成 /api/admin/users(相对路径)
# 问题:Nginx 无法正确代理
# ❌ 开发环境包含 /api
REACT_APP_API_BASE_URL=http://localhost:5001/api
# 结果:http://localhost:5001/api/api/admin/users
# 问题:多了一层 /api,后端无法匹配路由
✅ 正确配置
# ✅ 开发环境
REACT_APP_API_BASE_URL=http://localhost:5001
# ✅ 生产环境
REACT_APP_API_BASE_URL=https://d1kt.cn/api
🧪 验证方法
开发环境验证
# 1. 启动服务
npm run start
# 2. 浏览器访问
http://localhost:3001/admin
# 3. 打开 Network 面板,查看请求
# 应该看到:http://localhost:5001/api/admin/users ✅
生产环境验证
# 1. 构建并部署
npm run build
pm2 restart typing-backend
# 2. 浏览器访问
https://d1kt.cn/admin
# 3. 打开 Network 面板,查看请求
# 应该看到:https://d1kt.cn/api/api/admin/users ✅
📝 总结
- ✅ 统一使用
api对象进行所有 API 调用 - ✅ 通过环境变量控制不同环境的基础 URL
- ✅
getFullApiPath函数自动添加/api前缀 - ✅ 生产环境需要两个
/api:第一个给 Nginx,第二个给后端路由 - ✅ 开发环境和生产环境使用完全相同的代码逻辑
🌐 WebSocket 连接配置
WebSocket 路径配置
扫雷游戏的 WebSocket 连接需要正确处理路径前缀,以匹配 Nginx 代理配置:
客户端配置
REACT_APP_API_BASE_URL: API 基础地址(如/api或https://d1kt.cn/api)REACT_APP_CLIENT_URL: 客户端域名(如https://d1kt.cn)
服务器端配置
REACT_APP_API_BASE_URL: 与客户端相同的环境变量,用于确定 WebSocket 路径前缀
配置示例
开发环境 (.env)
REACT_APP_API_BASE_URL=http://localhost:5001
REACT_APP_CLIENT_URL=http://localhost:3001
生产环境 (.env.production)
REACT_APP_API_BASE_URL=/api
REACT_APP_CLIENT_URL=https://d1kt.cn
或使用完整 URL:
REACT_APP_API_BASE_URL=https://d1kt.cn/api
REACT_APP_CLIENT_URL=https://d1kt.cn
WebSocket 连接流程
开发环境:
1. 客户端连接: ws://localhost:5001/socket.io
2. 服务器监听: /socket.io
生产环境:
1. 客户端连接: wss://d1kt.cn/api/socket.io
2. Nginx 代理: location /api/ { proxy_pass http://localhost:5001/; }
3. 服务器监听: /socket.io
Nginx WebSocket 代理配置
确保 Nginx 配置包含 WebSocket 代理头:
location /api/ {
proxy_pass http://localhost:5001/;
proxy_http_version 1.1;
# WebSocket 代理头
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# 超时设置
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
故障排查
WebSocket 连接失败
- 检查 Nginx 配置:确认包含
Upgrade和Connection头 - 检查服务器日志:查看 Socket.IO 服务器是否启动
- 验证环境变量:确保
REACT_APP_API_BASE_URL正确设置
路径不匹配
- 客户端日志显示连接地址:
wss://d1kt.cn/api/socket.io - 服务器日志显示连接日志:
用户连接: [socket-id]
生产环境验证命令
# 测试 HTTP 握手
curl "https://d1kt.cn/api/socket.io/?EIO=4&transport=polling"
# 预期响应:
# 0{"sid":"xxx","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000}
已完成的修复
- ✅ 客户端 WebSocket 路径配置 (
getWebSocketPath()) - ✅ 服务器端 Socket.IO 路径配置 (
getSocketIoPath()) - ✅ Nginx WebSocket 代理配置示例
最后更新:2025-10-30