Files
d1kt/API_CONFIG_GUIDE.md

7.7 KiB
Raw Blame History

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

  1. 第一个 /apiNginx 反向代理的路径匹配

    location /api/ {
        proxy_pass http://localhost:5001/;
    }
    
    • 浏览器请求 https://d1kt.cn/api/xxx
    • Nginx 匹配到 /api/ 后,去掉这部分,转发到后端
    • 后端收到 http://localhost:5001/xxx
  2. 第二个 /api:后端路由的前缀

    • 后端所有路由都以 /api 开头
    • 例如:app.use('/api/admin', adminRoutes)
    • 所以需要请求 /api/admin/users
  3. 组合结果

    浏览器 → 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

🚀 部署步骤

生产环境部署

  1. 在服务器上创建 .env.production 文件

    cd /path/to/typing_practiceweb
    cp .env.production.example .env.production
    nano .env.production
    
  2. 配置生产环境变量

    REACT_APP_API_BASE_URL=https://d1kt.cn/api
    
  3. 构建前端

    npm run build
    

    这会自动读取 .env.production 文件

  4. 确认 Nginx 配置

    location /api/ {
        proxy_pass http://localhost:5001/;
    }
    
  5. 重启服务

    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 基础地址(如 /apihttps://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 连接失败

  1. 检查 Nginx 配置:确认包含 UpgradeConnection
  2. 检查服务器日志:查看 Socket.IO 服务器是否启动
  3. 验证环境变量:确保 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}

已完成的修复

  1. 客户端 WebSocket 路径配置 (getWebSocketPath())
  2. 服务器端 Socket.IO 路径配置 (getSocketIoPath())
  3. Nginx WebSocket 代理配置示例

最后更新2025-10-30