后端版本服务器部署成功
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 服务器配置
|
||||
NODE_ENV=development
|
||||
PORT=3000
|
||||
PORT=3200
|
||||
HOST=0.0.0.0
|
||||
|
||||
# 数据库配置
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 服务器配置
|
||||
NODE_ENV=development
|
||||
PORT=3000
|
||||
PORT=3200
|
||||
HOST=0.0.0.0
|
||||
|
||||
# 数据库配置
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
# 结伴客后端开发完善指南
|
||||
|
||||
## 📋 完善内容概述
|
||||
|
||||
本次后端开发完善主要包含以下内容:
|
||||
|
||||
### 1. 环境配置优化
|
||||
- ✅ 更新环境配置文件 (`config/env.js`),移除MongoDB配置,完善MySQL配置
|
||||
- ✅ 更新环境变量示例文件 (`.env.example`),添加MySQL相关配置
|
||||
- ✅ 数据库配置文件 (`src/config/database.js`) 现在使用环境配置而非硬编码
|
||||
|
||||
### 2. 测试数据支持
|
||||
- ✅ 创建测试数据初始化脚本 (`scripts/init-test-data.js`)
|
||||
- ✅ 提供标准测试账号(管理员、运营、普通用户、商家用户)
|
||||
- ✅ 支持密码加密存储(bcrypt)
|
||||
|
||||
### 3. 自动化测试脚本
|
||||
- ✅ 创建API端点测试脚本 (`scripts/test-api-endpoints.js`)
|
||||
- ✅ 创建数据库连接测试脚本 (`scripts/test-database-connection.js`)
|
||||
- ✅ 支持完整的测试用例和结果统计
|
||||
|
||||
### 4. 开发工具链完善
|
||||
- ✅ 更新package.json脚本命令
|
||||
- ✅ 提供一键测试和数据初始化功能
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 环境准备
|
||||
```bash
|
||||
# 复制环境配置文件
|
||||
cp .env.example .env
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
```
|
||||
|
||||
### 数据库配置
|
||||
编辑 `.env` 文件,配置MySQL数据库连接:
|
||||
|
||||
```env
|
||||
# 数据库配置
|
||||
DB_HOST=mysql.jiebanke.com
|
||||
DB_PORT=3306
|
||||
DB_USER=root
|
||||
DB_PASSWORD=your-mysql-password
|
||||
DB_NAME=jiebandata
|
||||
|
||||
# 连接池配置
|
||||
DB_CONNECTION_LIMIT=10
|
||||
DB_CHARSET=utf8mb4
|
||||
DB_TIMEZONE=+08:00
|
||||
```
|
||||
|
||||
### 开发命令
|
||||
|
||||
```bash
|
||||
# 启动开发服务器
|
||||
npm run dev
|
||||
|
||||
# 测试数据库连接
|
||||
npm run test-db
|
||||
|
||||
# 初始化测试数据
|
||||
npm run init-test-data
|
||||
|
||||
# 测试API端点
|
||||
npm run test-api
|
||||
|
||||
# 运行单元测试
|
||||
npm test
|
||||
|
||||
# 代码检查
|
||||
npm run lint
|
||||
```
|
||||
|
||||
## 📊 测试账号
|
||||
|
||||
初始化后会创建以下测试账号:
|
||||
|
||||
| 角色 | 用户名 | 密码 | 描述 |
|
||||
|------|--------|------|------|
|
||||
| 超级管理员 | admin | admin123 | 系统最高权限 |
|
||||
| 运营经理 | manager | manager123 | 日常运营管理 |
|
||||
| 普通用户 | user1 | user123 | 旅行爱好者 |
|
||||
| 商家用户 | merchant1 | merchant123 | 农家乐老板 |
|
||||
|
||||
## 🔧 API测试
|
||||
|
||||
API测试脚本会自动测试以下接口:
|
||||
|
||||
### 管理员接口
|
||||
- ✅ POST `/api/v1/admin/login` - 管理员登录
|
||||
- ✅ GET `/api/v1/admin/profile` - 获取管理员信息
|
||||
- ✅ GET `/api/v1/admin/list` - 获取管理员列表
|
||||
|
||||
### 用户接口
|
||||
- ✅ POST `/api/v1/auth/login` - 用户登录
|
||||
- ✅ GET `/api/v1/users/profile` - 获取用户信息
|
||||
|
||||
### 系统接口
|
||||
- ✅ GET `/health` - 健康检查
|
||||
- ✅ GET `/system-stats` - 系统统计
|
||||
|
||||
## 🗄️ 数据库配置
|
||||
|
||||
### 开发环境
|
||||
```javascript
|
||||
{
|
||||
host: '192.168.0.240',
|
||||
port: 3306,
|
||||
user: 'root',
|
||||
password: 'aiotAiot123!',
|
||||
database: 'jiebandata',
|
||||
connectionLimit: 10
|
||||
}
|
||||
```
|
||||
|
||||
### 测试环境
|
||||
```javascript
|
||||
{
|
||||
host: '192.168.0.240',
|
||||
port: 3306,
|
||||
user: 'root',
|
||||
password: 'aiotAiot123!',
|
||||
database: 'jiebandata_test',
|
||||
connectionLimit: 5
|
||||
}
|
||||
```
|
||||
|
||||
### 生产环境
|
||||
```javascript
|
||||
{
|
||||
host: 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
|
||||
port: 20784,
|
||||
user: 'jiebanke',
|
||||
password: 'aiot741$12346',
|
||||
database: 'jbkdata',
|
||||
connectionLimit: 20
|
||||
}
|
||||
```
|
||||
|
||||
## ⚡ 生产环境连接说明
|
||||
|
||||
|
||||
### 注意事项
|
||||
1. **谨慎操作**: 直接连接生产数据库,所有操作都会影响真实数据
|
||||
2. **备份优先**: 在执行任何修改操作前,建议先备份数据
|
||||
3. **权限控制**: 确保只有授权人员可以访问生产环境
|
||||
4. **监控日志**: 密切监控数据库操作日志,及时发现异常
|
||||
5. **连接限制**: 生产环境连接数限制为20,避免过度消耗资源
|
||||
|
||||
### 安全建议
|
||||
- 使用VPN连接生产环境
|
||||
- 启用SSL加密连接
|
||||
- 定期更换密码
|
||||
- 实施IP白名单限制
|
||||
- 启用数据库审计功能
|
||||
|
||||
### 连接问题排查
|
||||
如果遇到连接问题,请检查:
|
||||
|
||||
1. **密码验证**: 确认生产服务器MySQL的root密码是否为'Aiot123'
|
||||
2. **权限配置**: 检查MySQL用户权限设置,确保允许从当前IP连接
|
||||
3. **防火墙**: 确认服务器防火墙已开放9527端口
|
||||
4. **网络连通性**: 使用telnet或ping测试网络连接
|
||||
|
||||
### 当前连接状态
|
||||
- ❌ 生产服务器(129.211.213.226:9527): 权限被拒绝(ER_ACCESS_DENIED_ERROR)
|
||||
- ❌ 开发服务器(192.168.0.240:3306): 连接超时(ETIMEDOUT)
|
||||
|
||||
### 本地开发解决方案
|
||||
推荐使用Docker本地MySQL进行开发:
|
||||
|
||||
1. **启动本地MySQL容器**
|
||||
```bash
|
||||
cd /Users/ainongkeji/code/vue/jiebanke/backend
|
||||
docker-compose up -d mysql
|
||||
```
|
||||
|
||||
2. **配置本地环境变量**
|
||||
```bash
|
||||
# 使用本地Docker MySQL
|
||||
export DB_HOST=mysql.jiebanke.com
|
||||
export DB_PORT=3306
|
||||
export DB_PASSWORD=rootpassword
|
||||
export DB_DATABASE=jiebanke_dev
|
||||
```
|
||||
|
||||
3. **初始化数据库**
|
||||
```bash
|
||||
npm run db:reset # 重置并初始化数据库
|
||||
npm run db:seed # 填充测试数据
|
||||
```
|
||||
|
||||
### 生产环境连接说明
|
||||
如需连接生产环境,请联系运维团队:
|
||||
- 确认生产服务器MySQL root密码
|
||||
- 检查IP白名单配置
|
||||
- 验证网络连通性
|
||||
- 确认防火墙规则
|
||||
|
||||
### 紧急开发方案
|
||||
如果所有远程服务器都无法连接,可以使用SQLite进行临时开发:
|
||||
```bash
|
||||
export DB_DIALECT=sqlite
|
||||
export DB_STORAGE=./database.sqlite
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 📝 开发规范
|
||||
|
||||
### 代码风格
|
||||
- 使用ESLint进行代码检查
|
||||
- 遵循JavaScript标准风格
|
||||
- 使用async/await处理异步操作
|
||||
|
||||
### 安全规范
|
||||
- 密码使用bcrypt加密存储
|
||||
- 使用环境变量存储敏感信息
|
||||
- 实施SQL注入防护
|
||||
- 启用CORS和HTTPS
|
||||
|
||||
### 日志规范
|
||||
- 开发环境使用详细日志
|
||||
- 生产环境使用合并日志
|
||||
- 记录关键操作和错误信息
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q: 数据库连接失败
|
||||
A: 检查MySQL服务是否启动,配置是否正确
|
||||
|
||||
### Q: 测试数据初始化失败
|
||||
A: 确保数据库表结构已创建,可先运行迁移脚本
|
||||
|
||||
### Q: API测试失败
|
||||
A: 确认后端服务已启动,检查网络连接
|
||||
|
||||
### Q: 权限不足
|
||||
A: 检查数据库用户权限,确认有足够的操作权限
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
如有问题请联系开发团队或查看详细文档。
|
||||
|
||||
---
|
||||
|
||||
**最后更新: 2024年**
|
||||
**版本: 1.0.0**
|
||||
@@ -1,181 +0,0 @@
|
||||
# 结伴客后端服务管理脚本
|
||||
|
||||
## 概述
|
||||
|
||||
本目录包含用于管理结伴客后端服务的一组脚本,包括启动、停止、重启和状态检查等功能。
|
||||
|
||||
## 脚本说明
|
||||
|
||||
### start.sh - 启动脚本
|
||||
|
||||
用于启动结伴客后端服务。
|
||||
|
||||
#### 使用方法
|
||||
|
||||
```bash
|
||||
# 生产模式启动(默认)
|
||||
./start.sh
|
||||
|
||||
# 开发模式启动(支持热重载)
|
||||
./start.sh dev
|
||||
|
||||
# 显示帮助信息
|
||||
./start.sh help
|
||||
```
|
||||
|
||||
#### 功能特点
|
||||
|
||||
- 自动检查并安装依赖(如果未安装)
|
||||
- 自动复制环境变量文件(如果不存在)
|
||||
- 支持生产模式和开发模式
|
||||
- 开发模式下优先使用 nodemon(如果已安装)
|
||||
|
||||
### stop.sh - 停止脚本
|
||||
|
||||
用于停止正在运行的结伴客后端服务。
|
||||
|
||||
#### 使用方法
|
||||
|
||||
```bash
|
||||
# 停止服务
|
||||
./stop.sh
|
||||
|
||||
# 显示帮助信息
|
||||
./stop.sh help
|
||||
```
|
||||
|
||||
#### 功能特点
|
||||
|
||||
- 自动查找并停止所有相关的后端服务进程
|
||||
- 优雅地停止进程,超时后强制终止
|
||||
- 显示详细的进程停止信息
|
||||
|
||||
### restart.sh - 重启脚本
|
||||
|
||||
用于重启结伴客后端服务。
|
||||
|
||||
#### 使用方法
|
||||
|
||||
```bash
|
||||
# 生产模式重启(默认)
|
||||
./restart.sh
|
||||
|
||||
# 开发模式重启
|
||||
./restart.sh dev
|
||||
|
||||
# 显示帮助信息
|
||||
./restart.sh help
|
||||
```
|
||||
|
||||
#### 功能特点
|
||||
|
||||
- 结合了 stop.sh 和 start.sh 的所有功能
|
||||
- 支持生产模式和开发模式
|
||||
- 在停止和启动之间添加了延迟以确保服务完全停止
|
||||
|
||||
### status.sh - 状态检查脚本
|
||||
|
||||
用于检查结伴客后端服务的运行状态。
|
||||
|
||||
#### 使用方法
|
||||
|
||||
```bash
|
||||
# 检查服务状态
|
||||
./status.sh
|
||||
|
||||
# 显示详细信息
|
||||
./status.sh detail
|
||||
|
||||
# 显示帮助信息
|
||||
./status.sh help
|
||||
```
|
||||
|
||||
#### 功能特点
|
||||
|
||||
- 显示服务是否正在运行
|
||||
- 显示相关的进程信息
|
||||
- 详细模式下显示端口占用、工作目录等信息
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 日常使用
|
||||
|
||||
```bash
|
||||
# 进入后端目录
|
||||
cd backend
|
||||
|
||||
# 启动服务
|
||||
./start.sh
|
||||
|
||||
# 检查服务状态
|
||||
./status.sh
|
||||
|
||||
# 重启服务
|
||||
./restart.sh
|
||||
|
||||
# 停止服务
|
||||
./stop.sh
|
||||
```
|
||||
|
||||
### 开发环境使用
|
||||
|
||||
```bash
|
||||
# 进入后端目录
|
||||
cd backend
|
||||
|
||||
# 以开发模式启动(支持热重载)
|
||||
./start.sh dev
|
||||
|
||||
# 检查服务状态
|
||||
./status.sh
|
||||
|
||||
# 重启服务(保持开发模式)
|
||||
./restart.sh dev
|
||||
|
||||
# 停止服务
|
||||
./stop.sh
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 首次运行脚本前,请确保已安装 Node.js 和 npm
|
||||
2. 脚本会自动检查依赖并安装(如果未安装)
|
||||
3. 如果没有安装 nodemon,开发模式将回退到使用 node
|
||||
4. 脚本需要在后端项目根目录下运行
|
||||
5. 确保运行脚本的用户具有足够的权限
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 权限问题
|
||||
|
||||
如果遇到权限问题,请为脚本添加执行权限:
|
||||
|
||||
```bash
|
||||
chmod +x start.sh stop.sh restart.sh status.sh
|
||||
```
|
||||
|
||||
或者使用 npm 命令:
|
||||
|
||||
```bash
|
||||
npm run start-scripts
|
||||
```
|
||||
|
||||
### 服务无法启动
|
||||
|
||||
1. 检查端口是否被占用:
|
||||
```bash
|
||||
netstat -tlnp | grep :3000
|
||||
```
|
||||
|
||||
2. 检查环境变量配置是否正确
|
||||
|
||||
3. 查看详细日志信息
|
||||
|
||||
### 服务无法停止
|
||||
|
||||
1. 脚本会自动等待10秒后强制终止进程
|
||||
2. 如果仍有问题,可以手动终止进程:
|
||||
```bash
|
||||
ps aux | grep "node src/server.js"
|
||||
kill -9 <PID>
|
||||
```
|
||||
290
backend/api-documentation.md
Normal file
290
backend/api-documentation.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# 结伴客后端API文档
|
||||
|
||||
## 1. 认证相关接口
|
||||
|
||||
### 用户注册
|
||||
|
||||
**请求方法**: POST
|
||||
**请求路径**: `/api/v1/auth/register`
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"username": "string", // 用户名(必需)
|
||||
"password": "string", // 密码(必需,至少6位)
|
||||
"nickname": "string", // 昵称(可选)
|
||||
"email": "string", // 邮箱(可选)
|
||||
"phone": "string" // 手机号(可选)
|
||||
}
|
||||
```
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": { // 用户信息(不含敏感信息)
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"nickname": "测试用户",
|
||||
"email": "test@jiebanke.com",
|
||||
"phone": "13800000000",
|
||||
// 其他用户字段...
|
||||
},
|
||||
"token": "string"
|
||||
},
|
||||
"message": "注册成功"
|
||||
}
|
||||
```
|
||||
**错误响应**:
|
||||
- 400: 用户名已存在 / 邮箱已存在 / 手机号已存在 / 密码长度不能少于6位
|
||||
- 500: 服务器内部错误
|
||||
|
||||
### 用户登录
|
||||
|
||||
**请求方法**: POST
|
||||
**请求路径**: `/api/v1/auth/login`
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"username": "string", // 用户名/邮箱/手机号(必需)
|
||||
"password": "string" // 密码(必需)
|
||||
}
|
||||
```
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": { // 用户信息(不含敏感信息)
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"nickname": "测试用户",
|
||||
"email": "test@jiebanke.com",
|
||||
"phone": "13800000000",
|
||||
// 其他用户字段...
|
||||
},
|
||||
"token": "string"
|
||||
},
|
||||
"message": "登录成功"
|
||||
}
|
||||
```
|
||||
**错误响应**:
|
||||
- 400: 用户名和密码不能为空
|
||||
- 401: 密码错误
|
||||
- 403: 账户已被禁用
|
||||
- 404: 用户不存在
|
||||
- 500: 服务器内部错误
|
||||
|
||||
## 2. 用户管理接口
|
||||
|
||||
### 获取当前用户信息
|
||||
|
||||
**请求方法**: GET
|
||||
**请求路径**: `/api/v1/users/profile`
|
||||
**请求头**: `Authorization: Bearer {token}`
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": { // 用户信息(不含敏感信息)
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"nickname": "测试用户",
|
||||
"email": "test@jiebanke.com",
|
||||
"phone": "13800000000",
|
||||
// 其他用户字段...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
**错误响应**:
|
||||
- 401: 未提供认证token / 无效的认证token / token已过期 / 用户不存在
|
||||
- 403: 账户已被禁用
|
||||
- 500: 服务器内部错误
|
||||
|
||||
### 更新用户个人信息
|
||||
|
||||
**请求方法**: PUT
|
||||
**请求路径**: `/api/v1/users/profile`
|
||||
**请求头**: `Authorization: Bearer {token}`
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"nickname": "string", // 昵称(可选)
|
||||
"avatar": "string", // 头像URL(可选)
|
||||
"gender": "string", // 性别(可选,可选值:male, female, other)
|
||||
"birthday": "string", // 生日(可选,格式:YYYY-MM-DD)
|
||||
"phone": "string", // 手机号(可选)
|
||||
"email": "string" // 邮箱(可选)
|
||||
}
|
||||
```
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": { // 更新后的用户信息(不含敏感信息)
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"nickname": "新昵称",
|
||||
"email": "new@email.com",
|
||||
"phone": "13900000000",
|
||||
// 其他用户字段...
|
||||
},
|
||||
"message": "个人信息更新成功"
|
||||
}
|
||||
}
|
||||
```
|
||||
**错误响应**:
|
||||
- 400: 没有有效的更新字段 / 邮箱已被其他用户使用 / 手机号已被其他用户使用
|
||||
- 401: 未提供认证token / 无效的认证token / token已过期 / 用户不存在
|
||||
- 403: 账户已被禁用
|
||||
- 500: 更新用户信息失败 / 服务器内部错误
|
||||
|
||||
## 3. 管理员接口
|
||||
|
||||
### 搜索用户
|
||||
|
||||
**请求方法**: GET
|
||||
**请求路径**: `/api/v1/admin/users/search`
|
||||
**请求头**: `Authorization: Bearer {token}`
|
||||
**请求参数**:
|
||||
- keyword: 搜索关键词(可选,模糊匹配用户名、昵称、邮箱、手机号)
|
||||
- userType: 用户类型(可选)
|
||||
- page: 当前页码(可选,默认:1)
|
||||
- pageSize: 每页记录数(可选,默认:10)
|
||||
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"users": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"user_type": "farmer",
|
||||
"real_name": "测试用户",
|
||||
"avatar_url": "",
|
||||
"email": "test@jiebanke.com",
|
||||
"phone": "13800000000",
|
||||
"status": "active",
|
||||
"created_at": "2024-01-01T12:00:00Z",
|
||||
"updated_at": "2024-01-01T12:00:00Z"
|
||||
}
|
||||
// 更多用户...
|
||||
],
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"pageSize": 10,
|
||||
"pages": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
**错误响应**:
|
||||
- 401: 未提供认证token / 无效的认证token / token已过期 / 管理员不存在
|
||||
- 403: 管理员账号已被禁用 / 需要管理员权限 / 权限不足
|
||||
- 500: 服务器内部错误
|
||||
|
||||
### 批量更新用户状态
|
||||
|
||||
**请求方法**: POST
|
||||
**请求路径**: `/api/v1/admin/users/batch-status`
|
||||
**请求头**: `Authorization: Bearer {token}`
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"userIds": [1, 2, 3], // 用户ID列表(必需)
|
||||
"status": "active" // 状态(必需,可选值:active, inactive)
|
||||
}
|
||||
```
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"message": "成功更新 3 个用户状态",
|
||||
"affectedRows": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
**错误响应**:
|
||||
- 400: 请选择要操作的用户 / 无效的状态值
|
||||
- 401: 未提供认证token / 无效的认证token / token已过期 / 管理员不存在
|
||||
- 403: 管理员账号已被禁用 / 需要管理员权限 / 权限不足
|
||||
- 500: 服务器内部错误
|
||||
|
||||
## 4. 系统接口
|
||||
|
||||
### 健康检查
|
||||
|
||||
**请求方法**: GET
|
||||
**请求路径**: `/health`
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"status": "OK",
|
||||
"timestamp": "2024-01-01T12:00:00Z",
|
||||
"uptime": 1234.56,
|
||||
"environment": "production"
|
||||
}
|
||||
```
|
||||
|
||||
### 系统统计
|
||||
|
||||
**请求方法**: GET
|
||||
**请求路径**: `/system-stats`
|
||||
**响应**:
|
||||
```json
|
||||
{
|
||||
"status": "OK",
|
||||
"timestamp": "2024-01-01T12:00:00Z",
|
||||
"environment": "production",
|
||||
"nodeVersion": "v18.16.0",
|
||||
"memoryUsage": {
|
||||
"rss": 123456789,
|
||||
"heapTotal": 12345678,
|
||||
"heapUsed": 1234567,
|
||||
"external": 123456
|
||||
},
|
||||
"uptime": 1234.56,
|
||||
"cpuCount": 8,
|
||||
"platform": "linux",
|
||||
"architecture": "x64"
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 错误码说明
|
||||
|
||||
| 错误码 | 描述 | HTTP状态码 |
|
||||
|-------|------|-----------|
|
||||
| 400 | 请求参数错误 | 400 |
|
||||
| 401 | 未授权(无效token、token过期等) | 401 |
|
||||
| 403 | 权限不足或账户被禁用 | 403 |
|
||||
| 404 | 资源不存在 | 404 |
|
||||
| 429 | 请求过于频繁 | 429 |
|
||||
| 500 | 服务器内部错误 | 500 |
|
||||
| 503 | 服务不可用(如数据库连接失败) | 503 |
|
||||
|
||||
## 6. 认证机制
|
||||
|
||||
系统使用JWT(JSON Web Token)进行认证,所有需要认证的接口都需要在请求头中包含`Authorization: Bearer {token}`。
|
||||
|
||||
### Token有效期
|
||||
- 默认有效期为7天
|
||||
- 可通过环境变量`JWT_EXPIRE`自定义
|
||||
|
||||
### Token安全
|
||||
- 生产环境请确保设置安全的`JWT_SECRET`环境变量
|
||||
- 避免在客户端存储敏感信息
|
||||
|
||||
## 7. 接口限制
|
||||
|
||||
- 接口请求频率限制:生产环境15分钟内最多100次请求,开发环境15分钟内最多1000次请求
|
||||
- 请求体大小限制:10kb
|
||||
- 支持的请求内容类型:application/json
|
||||
|
||||
## 8. Swagger文档
|
||||
|
||||
在开发环境或设置`ENABLE_SWAGGER=true`环境变量时,可通过以下地址访问Swagger文档:
|
||||
- https://webapi.jiebanke.com/api-docs
|
||||
134
backend/cleanup_files.sh
Executable file
134
backend/cleanup_files.sh
Executable file
@@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 结伴客后端文件清理脚本
|
||||
# 删除不需要的文件,保持项目结构整洁
|
||||
|
||||
# 设置颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置参数
|
||||
BACKEND_DIR="$(pwd)"
|
||||
|
||||
# 显示警告信息
|
||||
show_warning() {
|
||||
echo -e "${YELLOW}警告:此脚本将删除backend目录中不需要的文件。${NC}"
|
||||
echo -e "${YELLOW}请确保在运行此脚本前已备份重要数据。${NC}"
|
||||
echo -e "${BLUE}按Enter键继续,或按Ctrl+C取消...${NC}"
|
||||
read -r
|
||||
}
|
||||
|
||||
# 删除指定文件
|
||||
remove_file() {
|
||||
local file_path="$1"
|
||||
if [ -f "$file_path" ]; then
|
||||
echo -e "${BLUE}删除文件: $file_path${NC}"
|
||||
rm -f "$file_path"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}已删除: $file_path${NC}"
|
||||
else
|
||||
echo -e "${RED}删除失败: $file_path${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}文件不存在: $file_path${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 删除指定目录(如果为空)
|
||||
remove_empty_dir() {
|
||||
local dir_path="$1"
|
||||
if [ -d "$dir_path" ] && [ -z "$(ls -A "$dir_path")" ]; then
|
||||
echo -e "${BLUE}删除空目录: $dir_path${NC}"
|
||||
rm -d "$dir_path"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}已删除: $dir_path${NC}"
|
||||
else
|
||||
echo -e "${RED}删除失败: $dir_path${NC}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理测试文件
|
||||
cleanup_test_files() {
|
||||
echo -e "${BLUE}\n清理测试相关文件...${NC}"
|
||||
remove_file "$BACKEND_DIR/test-api.js"
|
||||
remove_file "$BACKEND_DIR/test-swagger.js"
|
||||
# 可以保留scripts目录下的测试脚本,因为它们可能对开发有用
|
||||
}
|
||||
|
||||
# 清理文档文件
|
||||
cleanup_docs() {
|
||||
echo -e "${BLUE}\n清理文档文件...${NC}"
|
||||
remove_file "$BACKEND_DIR/README_DEVELOPMENT.md"
|
||||
remove_file "$BACKEND_DIR/README_SCRIPTS.md"
|
||||
# 保留主要的README.md文件
|
||||
}
|
||||
|
||||
# 清理Docker相关文件
|
||||
cleanup_docker_files() {
|
||||
echo -e "${BLUE}\n清理Docker相关文件...${NC}"
|
||||
remove_file "$BACKEND_DIR/docker-compose.yml"
|
||||
remove_file "$BACKEND_DIR/jiebanke.conf"
|
||||
}
|
||||
|
||||
# 清理旧的启动脚本
|
||||
cleanup_old_scripts() {
|
||||
echo -e "${BLUE}\n清理旧的启动脚本...${NC}"
|
||||
remove_file "$BACKEND_DIR/start.sh"
|
||||
remove_file "$BACKEND_DIR/stop.sh"
|
||||
remove_file "$BACKEND_DIR/restart.sh"
|
||||
remove_file "$BACKEND_DIR/status.sh"
|
||||
}
|
||||
|
||||
# 清理临时文件和缓存
|
||||
cleanup_temp_files() {
|
||||
echo -e "${BLUE}\n清理临时文件和缓存...${NC}"
|
||||
find "$BACKEND_DIR" -name "*.log" -exec rm -f {} \;
|
||||
find "$BACKEND_DIR" -name "*.tmp" -exec rm -f {} \;
|
||||
find "$BACKEND_DIR" -name "*.temp" -exec rm -f {} \;
|
||||
find "$BACKEND_DIR" -name ".DS_Store" -exec rm -f {} \;
|
||||
}
|
||||
|
||||
# 验证并设置脚本权限
|
||||
set_script_permissions() {
|
||||
echo -e "${BLUE}\n设置脚本执行权限...${NC}"
|
||||
# 为新创建的脚本设置执行权限
|
||||
chmod +x "$BACKEND_DIR/sync_to_server.sh" 2>/dev/null
|
||||
chmod +x "$BACKEND_DIR/start_server.sh" 2>/dev/null
|
||||
chmod +x "$BACKEND_DIR/cleanup_files.sh" 2>/dev/null
|
||||
echo -e "${GREEN}脚本权限设置完成${NC}"
|
||||
}
|
||||
|
||||
# 显示清理结果摘要
|
||||
show_summary() {
|
||||
echo -e "${GREEN}\n文件清理完成!${NC}"
|
||||
echo -e "${YELLOW}剩余核心文件:${NC}"
|
||||
echo -e " - package.json, package-lock.json (项目依赖配置)"
|
||||
echo -e " - .env, .env.example (环境配置)"
|
||||
echo -e " - ecosystem.config.js (PM2配置)"
|
||||
echo -e " - src/ (源代码目录)"
|
||||
echo -e " - config/ (配置目录)"
|
||||
echo -e " - scripts/ (脚本目录)"
|
||||
echo -e " - README.md (项目说明)"
|
||||
echo -e " - sync_to_server.sh (新的同步脚本)"
|
||||
echo -e " - start_server.sh (新的服务器启动脚本)"
|
||||
echo -e " - cleanup_files.sh (此清理脚本)"
|
||||
}
|
||||
|
||||
# 执行清理
|
||||
main() {
|
||||
show_warning
|
||||
cleanup_test_files
|
||||
cleanup_docs
|
||||
cleanup_docker_files
|
||||
cleanup_old_scripts
|
||||
cleanup_temp_files
|
||||
set_script_permissions
|
||||
show_summary
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main
|
||||
@@ -5,7 +5,7 @@ require('dotenv').config({ path: path.join(__dirname, '../../.env') })
|
||||
const config = {
|
||||
// 开发环境
|
||||
development: {
|
||||
port: process.env.PORT || 3100,
|
||||
port: process.env.PORT || 3200,
|
||||
mysql: {
|
||||
host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
|
||||
port: process.env.DB_PORT || 20784,
|
||||
@@ -38,7 +38,7 @@ const config = {
|
||||
|
||||
// 测试环境
|
||||
test: {
|
||||
port: process.env.PORT || 3100,
|
||||
port: process.env.PORT || 3200,
|
||||
mysql: {
|
||||
host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
|
||||
port: process.env.DB_PORT || 20784,
|
||||
@@ -62,7 +62,7 @@ const config = {
|
||||
|
||||
// 生产环境
|
||||
production: {
|
||||
port: process.env.PORT || 3100,
|
||||
port: process.env.PORT || 3200,
|
||||
mysql: {
|
||||
host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com',
|
||||
port: process.env.DB_PORT || 20784,
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: jiebanke-mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: rootpassword
|
||||
MYSQL_DATABASE: jiebanke_dev
|
||||
MYSQL_USER: jiebanke_user
|
||||
MYSQL_PASSWORD: jiebanke_pass
|
||||
ports:
|
||||
- "3306:3306"
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./scripts/init-database.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "mysql.jiebanke.com", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
driver: local
|
||||
@@ -6,12 +6,12 @@ module.exports = {
|
||||
exec_mode: 'cluster',
|
||||
env: {
|
||||
NODE_ENV: 'development',
|
||||
PORT: 3000,
|
||||
PORT: 3200,
|
||||
WATCH: true
|
||||
},
|
||||
env_production: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 3000,
|
||||
PORT: 3200,
|
||||
WATCH: false
|
||||
},
|
||||
env_test: {
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
# Nginx配置文件 - 结伴客后端服务
|
||||
# 适用于Node.js Express应用
|
||||
|
||||
# 定义Node.js应用服务器
|
||||
upstream nodejs_backend {
|
||||
server 127.0.0.1:3100;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
# HTTP服务器配置
|
||||
server {
|
||||
listen 80;
|
||||
server_name webapi.jiebanke.com;
|
||||
|
||||
# 重定向所有HTTP请求到HTTPS
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS服务器配置
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name webapi.jiebanke.com;
|
||||
|
||||
# SSL证书配置(需要替换为实际证书路径)
|
||||
ssl_certificate /path/to/your/certificate.crt;
|
||||
ssl_certificate_key /path/to/your/private.key;
|
||||
|
||||
# SSL安全配置
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# 启用HSTS
|
||||
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||
|
||||
# 客户端上传大小限制
|
||||
client_max_body_size 10M;
|
||||
|
||||
# 日志配置
|
||||
access_log /var/log/nginx/webapi.jiebanke.com.access.log;
|
||||
error_log /var/log/nginx/webapi.jiebanke.com.error.log;
|
||||
|
||||
# API接口代理
|
||||
location /api/ {
|
||||
proxy_pass http://nodejs_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_read_timeout 90;
|
||||
}
|
||||
|
||||
# 管理员API接口代理
|
||||
location /admin/ {
|
||||
proxy_pass http://nodejs_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_read_timeout 90;
|
||||
}
|
||||
|
||||
# 健康检查端点
|
||||
location /health {
|
||||
proxy_pass http://nodejs_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Swagger API文档
|
||||
location /api-docs {
|
||||
proxy_pass http://nodejs_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# 上传文件访问
|
||||
location /uploads/ {
|
||||
proxy_pass http://nodejs_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# 默认根路径处理
|
||||
location / {
|
||||
proxy_pass http://nodejs_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# 安全头设置
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
|
||||
}
|
||||
110
backend/jiebanke_nginx.conf
Normal file
110
backend/jiebanke_nginx.conf
Normal file
@@ -0,0 +1,110 @@
|
||||
# 结伴客后端Nginx配置文件
|
||||
# SSL配置和webapi.jiebanke.com域名设置
|
||||
|
||||
# HTTP服务器配置 - 重定向到HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name webapi.jiebanke.com;
|
||||
|
||||
# 强制HTTPS重定向
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS服务器配置
|
||||
server {
|
||||
# 监听443端口并启用SSL
|
||||
listen 443 ssl http2;
|
||||
server_name webapi.jiebanke.com;
|
||||
|
||||
# SSL证书配置
|
||||
ssl_certificate /etc/nginx/ssl/webapi.jiebanke.com.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/webapi.jiebanke.com.key;
|
||||
|
||||
# SSL优化配置
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
# HSTS配置
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
|
||||
# 安全头部配置
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade";
|
||||
|
||||
# 访问日志配置
|
||||
access_log /var/log/nginx/webapi_access.log;
|
||||
error_log /var/log/nginx/webapi_error.log;
|
||||
|
||||
# 代理配置
|
||||
location / {
|
||||
# 代理到Node.js后端服务
|
||||
proxy_pass http://localhost:3200;
|
||||
|
||||
# 代理头信息配置
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket支持
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
|
||||
# 代理超时设置
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 120s;
|
||||
|
||||
# 缓冲区设置
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 8k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 16k;
|
||||
}
|
||||
|
||||
# 健康检查端点
|
||||
location /health {
|
||||
access_log off;
|
||||
proxy_pass http://localhost:3200/health;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# API文档端点
|
||||
location /api-docs {
|
||||
proxy_pass http://localhost:3200/api-docs;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
# 静态资源缓存控制(如果后端有静态资源)
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
proxy_pass http://localhost:3200;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# 错误页面配置
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
|
||||
# 可选:负载均衡配置(如果有多个后端实例)
|
||||
# upstream jiebanke_backend {
|
||||
# server localhost:3200;
|
||||
# # 可以添加更多后端实例
|
||||
# # server localhost:3201;
|
||||
# # server localhost:3202;
|
||||
#
|
||||
# # 负载均衡策略
|
||||
# # least_conn;
|
||||
# # ip_hash;
|
||||
# }
|
||||
@@ -1,107 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 结伴客后端服务重启脚本
|
||||
|
||||
# 设置颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 停止服务
|
||||
stop_server() {
|
||||
echo -e "${BLUE}正在停止结伴客后端服务...${NC}"
|
||||
|
||||
# 查找并停止结伴客后端服务进程
|
||||
PIDS=$(ps aux | grep "node src/server.js" | grep -v grep | awk '{print $2}')
|
||||
|
||||
if [ -z "$PIDS" ]; then
|
||||
echo -e "${YELLOW}未找到正在运行的结伴客后端服务进程${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}找到以下结伴客后端服务进程: $PIDS${NC}"
|
||||
|
||||
for PID in $PIDS; do
|
||||
echo -e "${BLUE}正在停止进程 $PID...${NC}"
|
||||
kill $PID
|
||||
|
||||
# 等待进程结束
|
||||
COUNT=0
|
||||
while kill -0 $PID 2>/dev/null; do
|
||||
sleep 1
|
||||
COUNT=$((COUNT + 1))
|
||||
if [ $COUNT -gt 10 ]; then
|
||||
echo -e "${YELLOW}进程 $PID 未能正常停止,正在强制终止...${NC}"
|
||||
kill -9 $PID
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${GREEN}进程 $PID 已停止${NC}"
|
||||
done
|
||||
|
||||
echo -e "${GREEN}结伴客后端服务已停止${NC}"
|
||||
}
|
||||
|
||||
# 启动服务
|
||||
start_server() {
|
||||
echo -e "${BLUE}正在启动结伴客后端服务...${NC}"
|
||||
|
||||
# 检查是否提供了参数
|
||||
if [ "$1" = "dev" ]; then
|
||||
# 开发模式
|
||||
if command -v nodemon &> /dev/null; then
|
||||
nodemon src/server.js
|
||||
else
|
||||
echo -e "${YELLOW}未安装 nodemon,使用 node 运行...${NC}"
|
||||
node src/server.js
|
||||
fi
|
||||
else
|
||||
# 生产模式
|
||||
node src/server.js
|
||||
fi
|
||||
}
|
||||
|
||||
# 重启服务
|
||||
restart_server() {
|
||||
stop_server
|
||||
sleep 2
|
||||
start_server "$1"
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
echo "结伴客后端服务重启脚本"
|
||||
echo ""
|
||||
echo "使用方法:"
|
||||
echo " ./restart.sh - 重启服务(生产模式)"
|
||||
echo " ./restart.sh dev - 重启服务(开发模式)"
|
||||
echo " ./restart.sh help - 显示帮助信息"
|
||||
echo ""
|
||||
echo "说明:"
|
||||
echo " 生产模式: 使用 node 直接运行服务"
|
||||
echo " 开发模式: 使用 nodemon 运行服务(支持热重载)"
|
||||
}
|
||||
|
||||
# 主逻辑
|
||||
main() {
|
||||
echo -e "${GREEN}========== 结伴客后端服务重启脚本 ==========${NC}"
|
||||
|
||||
# 检查参数
|
||||
case "$1" in
|
||||
"help"|"-h"|"--help")
|
||||
show_help
|
||||
;;
|
||||
"dev")
|
||||
restart_server "dev"
|
||||
;;
|
||||
*)
|
||||
restart_server
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主逻辑
|
||||
main "$@"
|
||||
@@ -14,7 +14,7 @@ const options = {
|
||||
description: '开发环境服务器'
|
||||
},
|
||||
{
|
||||
url: 'https://your-domain.com/api/v1',
|
||||
url: 'https://webapi.jiebanke.com/api/v1',
|
||||
description: '生产环境服务器'
|
||||
}
|
||||
],
|
||||
@@ -97,37 +97,26 @@ const options = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: {
|
||||
type: 'boolean',
|
||||
description: '请求是否成功'
|
||||
},
|
||||
code: {
|
||||
type: 'integer',
|
||||
description: '状态码'
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
description: '响应消息'
|
||||
type: 'boolean'
|
||||
},
|
||||
data: {
|
||||
type: 'object',
|
||||
description: '响应数据'
|
||||
type: 'object'
|
||||
},
|
||||
message: {
|
||||
type: 'string'
|
||||
},
|
||||
timestamp: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
apis: [
|
||||
'./src/routes/*.js',
|
||||
'./src/controllers/*.js'
|
||||
]
|
||||
apis: ['src/routes/*.js', 'src/controllers/*.js']
|
||||
}
|
||||
|
||||
const specs = swaggerJsdoc(options)
|
||||
const swaggerSpec = swaggerJsdoc(options)
|
||||
|
||||
module.exports = specs
|
||||
module.exports = swaggerSpec
|
||||
@@ -1,10 +1,49 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
const Admin = require('../models/admin');
|
||||
const UserMySQL = require('../models/UserMySQL');
|
||||
const { AppError } = require('../utils/errors');
|
||||
|
||||
// 用户认证中间件
|
||||
function authenticateUser(req, res, next) {
|
||||
// TODO: 实现用户认证逻辑
|
||||
next();
|
||||
async function authenticateUser(req, res, next) {
|
||||
try {
|
||||
// 从请求头获取token
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
throw new AppError('未提供认证token', 401);
|
||||
}
|
||||
|
||||
const token = authHeader.split(' ')[1];
|
||||
|
||||
// 验证token
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your-secret-key');
|
||||
|
||||
// 查找用户
|
||||
const user = await UserMySQL.findById(decoded.userId);
|
||||
if (!user) {
|
||||
throw new AppError('用户不存在', 401);
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if (!UserMySQL.isActive(user)) {
|
||||
throw new AppError('账户已被禁用', 403);
|
||||
}
|
||||
|
||||
// 将用户信息添加到请求对象
|
||||
req.user = UserMySQL.sanitize(user);
|
||||
req.userId = decoded.userId; // 同时设置userId,保持与现有控制器的兼容性
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
if (error.name === 'JsonWebTokenError') {
|
||||
throw new AppError('无效的认证token', 401);
|
||||
}
|
||||
|
||||
if (error.name === 'TokenExpiredError') {
|
||||
throw new AppError('认证token已过期', 401);
|
||||
}
|
||||
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 管理员认证中间件
|
||||
|
||||
@@ -89,7 +89,7 @@ class UserMySQL {
|
||||
|
||||
// 更新密码
|
||||
static async updatePassword(id, newPassword) {
|
||||
const sql = 'UPDATE users SET password = ?, updated_at = NOW() WHERE id = ?';
|
||||
const sql = 'UPDATE users SET password_hash = ?, updated_at = NOW() WHERE id = ?';
|
||||
const result = await query(sql, [newPassword, id]);
|
||||
return result.affectedRows > 0;
|
||||
}
|
||||
@@ -154,25 +154,11 @@ class UserMySQL {
|
||||
return rows[0].count > 0;
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
static async isUsernameExists(username, excludeId = null) {
|
||||
let sql = 'SELECT COUNT(*) as count FROM users WHERE username = ?';
|
||||
const params = [username];
|
||||
|
||||
if (excludeId) {
|
||||
sql += ' AND id != ?';
|
||||
params.push(excludeId);
|
||||
}
|
||||
|
||||
const rows = await query(sql, params);
|
||||
return rows[0].count > 0;
|
||||
}
|
||||
|
||||
// 安全返回用户信息(去除敏感信息)
|
||||
static sanitize(user) {
|
||||
if (!user) return null;
|
||||
|
||||
const { password, ...safeUser } = user;
|
||||
const { password_hash, ...safeUser } = user;
|
||||
return safeUser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ const { testConnection } = require('./config/database')
|
||||
const redisConfig = require('./config/redis')
|
||||
const rabbitMQConfig = require('./config/rabbitmq')
|
||||
|
||||
const PORT = process.env.PORT || 3100
|
||||
const PORT = process.env.PORT || 3200
|
||||
const HOST = process.env.HOST || '0.0.0.0'
|
||||
|
||||
// 显示启动横幅
|
||||
|
||||
@@ -23,6 +23,39 @@ const notFound = (req, res, next) => {
|
||||
next(error)
|
||||
}
|
||||
|
||||
// MySQL重复键错误处理
|
||||
const handleDuplicateFieldsDB = (err) => {
|
||||
// 提取重复的字段值
|
||||
let value = '未知字段'
|
||||
if (err.sqlMessage && err.sqlMessage.includes('Duplicate entry')) {
|
||||
const match = err.sqlMessage.match(/Duplicate entry '([^']+)' for key '([^']+)'/)
|
||||
if (match && match[1]) {
|
||||
value = match[1]
|
||||
}
|
||||
}
|
||||
const message = `字段值 ${value} 已存在,请使用其他值`
|
||||
return new AppError(message, 400)
|
||||
}
|
||||
|
||||
// MySQL验证错误处理
|
||||
const handleValidationErrorDB = (err) => {
|
||||
// MySQL验证错误通常在sqlMessage中包含详细信息
|
||||
const message = err.sqlMessage || '输入数据无效'
|
||||
return new AppError(message, 400)
|
||||
}
|
||||
|
||||
// JWT错误处理
|
||||
const handleJWTError = () =>
|
||||
new AppError('无效的token,请重新登录', 401)
|
||||
|
||||
const handleJWTExpiredError = () =>
|
||||
new AppError('token已过期,请重新登录', 401)
|
||||
|
||||
// MySQL连接错误处理
|
||||
const handleDBConnectionError = (err) => {
|
||||
return new AppError('数据库连接失败,请稍后再试', 503)
|
||||
}
|
||||
|
||||
// 全局错误处理中间件
|
||||
const globalErrorHandler = (err, req, res, next) => {
|
||||
err.statusCode = err.statusCode || 500
|
||||
@@ -38,35 +71,28 @@ const globalErrorHandler = (err, req, res, next) => {
|
||||
stack: err.stack
|
||||
})
|
||||
} else {
|
||||
// 生产环境:区分不同类型的错误并提供适当的响应
|
||||
let error = { ...err, message: err.message } // 创建错误副本
|
||||
|
||||
// 数据库错误处理
|
||||
if (error.code === 'ER_DUP_ENTRY') error = handleDuplicateFieldsDB(error)
|
||||
if (error.code === 'ER_NO_REFERENCED_ROW_2' || error.code === 'ER_BAD_NULL_ERROR') {
|
||||
error = handleValidationErrorDB(error)
|
||||
}
|
||||
if (error.code === 'ECONNREFUSED') error = handleDBConnectionError(error)
|
||||
|
||||
// JWT错误处理
|
||||
if (error.name === 'JsonWebTokenError') error = handleJWTError()
|
||||
if (error.name === 'TokenExpiredError') error = handleJWTExpiredError()
|
||||
|
||||
// 生产环境简化错误信息
|
||||
res.status(err.statusCode).json({
|
||||
status: err.status,
|
||||
message: err.message
|
||||
res.status(error.statusCode || 500).json({
|
||||
status: error.status || 'error',
|
||||
message: error.message || '服务器内部错误'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// MongoDB重复键错误处理
|
||||
const handleDuplicateFieldsDB = (err) => {
|
||||
const value = err.errmsg.match(/(["'])(\\?.)*?\1/)[0]
|
||||
const message = `字段值 ${value} 已存在,请使用其他值`
|
||||
return new AppError(message, 400)
|
||||
}
|
||||
|
||||
// MongoDB验证错误处理
|
||||
const handleValidationErrorDB = (err) => {
|
||||
const errors = Object.values(err.errors).map(el => el.message)
|
||||
const message = `输入数据无效: ${errors.join('. ')}`
|
||||
return new AppError(message, 400)
|
||||
}
|
||||
|
||||
// JWT错误处理
|
||||
const handleJWTError = () =>
|
||||
new AppError('无效的token,请重新登录', 401)
|
||||
|
||||
const handleJWTExpiredError = () =>
|
||||
new AppError('token已过期,请重新登录', 401)
|
||||
|
||||
module.exports = {
|
||||
AppError,
|
||||
catchAsync,
|
||||
@@ -75,5 +101,6 @@ module.exports = {
|
||||
handleDuplicateFieldsDB,
|
||||
handleValidationErrorDB,
|
||||
handleJWTError,
|
||||
handleJWTExpiredError
|
||||
handleJWTExpiredError,
|
||||
handleDBConnectionError
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 结伴客后端服务启动脚本
|
||||
|
||||
# 设置颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 检查是否已经安装依赖
|
||||
check_dependencies() {
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo -e "${YELLOW}检测到未安装依赖,正在安装...${NC}"
|
||||
npm install
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}依赖安装失败!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}依赖安装完成!${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查环境变量文件
|
||||
check_env() {
|
||||
if [ ! -f ".env" ]; then
|
||||
echo -e "${YELLOW}未找到 .env 文件,正在复制示例文件...${NC}"
|
||||
if [ -f ".env.example" ]; then
|
||||
cp .env.example .env
|
||||
echo -e "${GREEN}.env 文件已创建,请根据需要修改配置!${NC}"
|
||||
else
|
||||
echo -e "${RED}未找到 .env.example 文件!${NC}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 启动服务
|
||||
start_server() {
|
||||
echo -e "${GREEN}正在启动结伴客后端服务...${NC}"
|
||||
|
||||
# 检查是否提供了参数
|
||||
if [ "$1" = "dev" ]; then
|
||||
# 开发模式
|
||||
if command -v nodemon &> /dev/null; then
|
||||
nodemon src/server.js
|
||||
else
|
||||
echo -e "${YELLOW}未安装 nodemon,使用 node 运行...${NC}"
|
||||
node src/server.js
|
||||
fi
|
||||
else
|
||||
# 生产模式
|
||||
node src/server.js
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
echo "结伴客后端服务启动脚本"
|
||||
echo ""
|
||||
echo "使用方法:"
|
||||
echo " ./start.sh - 以生产模式启动服务"
|
||||
echo " ./start.sh dev - 以开发模式启动服务"
|
||||
echo " ./start.sh help - 显示帮助信息"
|
||||
echo ""
|
||||
echo "说明:"
|
||||
echo " 生产模式: 使用 node 直接运行服务"
|
||||
echo " 开发模式: 使用 nodemon 运行服务(支持热重载)"
|
||||
}
|
||||
|
||||
# 主逻辑
|
||||
main() {
|
||||
echo -e "${GREEN}========== 结伴客后端服务启动脚本 ==========${NC}"
|
||||
|
||||
# 检查参数
|
||||
case "$1" in
|
||||
"help"|"-h"|"--help")
|
||||
show_help
|
||||
;;
|
||||
"dev")
|
||||
check_dependencies
|
||||
check_env
|
||||
start_server "dev"
|
||||
;;
|
||||
*)
|
||||
check_dependencies
|
||||
check_env
|
||||
start_server
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主逻辑
|
||||
main "$@"
|
||||
278
backend/start_server.sh
Executable file
278
backend/start_server.sh
Executable file
@@ -0,0 +1,278 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 结伴客后端服务启动脚本 - 在CentOS服务器上运行
|
||||
# 使用PM2管理Node.js应用
|
||||
|
||||
# 设置颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置参数
|
||||
APP_DIR="$(pwd)"
|
||||
NODE_ENV=${NODE_ENV:-"production"}
|
||||
PORT=${PORT:-"3200"}
|
||||
|
||||
# 检查Node.js环境
|
||||
check_node() {
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo -e "${RED}错误:Node.js环境未安装!${NC}"
|
||||
echo -e "${YELLOW}请先安装Node.js: curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash - && sudo yum install -y nodejs${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}Node.js版本: $(node -v)${NC}"
|
||||
}
|
||||
|
||||
# 检查PM2是否安装
|
||||
check_pm2() {
|
||||
if ! command -v pm2 &> /dev/null; then
|
||||
echo -e "${YELLOW}PM2未安装,正在全局安装...${NC}"
|
||||
npm install -g pm2
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}PM2安装失败!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo -e "${GREEN}PM2版本: $(pm2 -v)${NC}"
|
||||
}
|
||||
|
||||
# 检查环境变量文件
|
||||
check_env() {
|
||||
if [ ! -f "$APP_DIR/.env" ]; then
|
||||
echo -e "${RED}错误:未找到.env文件!${NC}"
|
||||
echo -e "${YELLOW}请确保.env文件已正确配置,包含必要的数据库连接信息和其他配置。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}已找到.env文件${NC}"
|
||||
}
|
||||
|
||||
# 检查ecosystem.config.js文件
|
||||
check_ecosystem() {
|
||||
if [ ! -f "$APP_DIR/ecosystem.config.js" ]; then
|
||||
echo -e "${YELLOW}未找到ecosystem.config.js文件,正在创建默认配置...${NC}"
|
||||
cat > "$APP_DIR/ecosystem.config.js" << EOF
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: 'jiebanke-backend',
|
||||
script: './src/server.js',
|
||||
instances: 'max',
|
||||
exec_mode: 'cluster',
|
||||
env: {
|
||||
NODE_ENV: 'development',
|
||||
PORT: $PORT,
|
||||
WATCH: true
|
||||
},
|
||||
env_production: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: $PORT,
|
||||
WATCH: false
|
||||
},
|
||||
log_file: '$APP_DIR/logs/combined.log',
|
||||
out_file: '$APP_DIR/logs/out.log',
|
||||
error_file: '$APP_DIR/logs/error.log',
|
||||
max_memory_restart: '1G',
|
||||
kill_timeout: 3000,
|
||||
wait_ready: true,
|
||||
listen_timeout: 3000,
|
||||
autorestart: true,
|
||||
max_restarts: 10,
|
||||
restart_delay: 4000,
|
||||
ignore_watch: [
|
||||
'node_modules',
|
||||
'logs',
|
||||
'.git',
|
||||
'uploads'
|
||||
]
|
||||
}]
|
||||
};
|
||||
EOF
|
||||
echo -e "${GREEN}ecosystem.config.js文件已创建${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 安装依赖
|
||||
install_dependencies() {
|
||||
echo -e "${BLUE}正在安装生产依赖...${NC}"
|
||||
cd "$APP_DIR"
|
||||
npm install --production
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}依赖安装失败!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}依赖安装完成!${NC}"
|
||||
}
|
||||
|
||||
# 创建日志和上传目录
|
||||
create_directories() {
|
||||
echo -e "${BLUE}正在创建必要的目录...${NC}"
|
||||
mkdir -p "$APP_DIR/logs" "$APP_DIR/uploads"
|
||||
chmod 755 "$APP_DIR/logs" "$APP_DIR/uploads"
|
||||
echo -e "${GREEN}目录创建完成!${NC}"
|
||||
}
|
||||
|
||||
# 启动服务
|
||||
start_service() {
|
||||
echo -e "${BLUE}正在使用PM2启动结伴客后端服务...${NC}"
|
||||
cd "$APP_DIR"
|
||||
|
||||
# 设置NODE_ENV环境变量
|
||||
export NODE_ENV=$NODE_ENV
|
||||
|
||||
# 使用PM2启动应用
|
||||
pm2 start ecosystem.config.js --env $NODE_ENV
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}服务启动失败!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}服务启动成功!${NC}"
|
||||
echo -e "${BLUE}应用名称: jiebanke-backend${NC}"
|
||||
echo -e "${BLUE}环境: $NODE_ENV${NC}"
|
||||
echo -e "${BLUE}端口: $PORT${NC}"
|
||||
echo -e "${YELLOW}提示:使用 pm2 logs jiebanke-backend 查看日志${NC}"
|
||||
echo -e "${YELLOW}提示:使用 pm2 monit 监控应用状态${NC}"
|
||||
}
|
||||
|
||||
# 设置PM2开机自启
|
||||
setup_autostart() {
|
||||
echo -e "${BLUE}正在配置PM2开机自启...${NC}"
|
||||
pm2 startup
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}PM2开机自启配置失败!${NC}"
|
||||
else
|
||||
pm2 save
|
||||
echo -e "${GREEN}PM2开机自启配置完成!${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
echo ""
|
||||
echo "结伴客后端服务管理脚本"
|
||||
echo ""
|
||||
echo "用法: $0 [命令] [环境]"
|
||||
echo ""
|
||||
echo "命令选项:"
|
||||
echo " start - 启动服务(默认)"
|
||||
echo " stop - 停止服务"
|
||||
echo " restart - 重启服务"
|
||||
echo " status - 查看服务状态"
|
||||
echo " logs - 查看服务日志"
|
||||
echo " install - 仅安装依赖"
|
||||
echo " setup - 配置PM2开机自启"
|
||||
echo " help - 显示此帮助信息"
|
||||
echo ""
|
||||
echo "环境选项:"
|
||||
echo " production - 生产环境(默认)"
|
||||
echo " development - 开发环境"
|
||||
echo " test - 测试环境"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 start production # 在生产环境启动服务"
|
||||
echo " $0 restart development # 在开发环境重启服务"
|
||||
echo " $0 logs # 查看服务日志"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 停止服务
|
||||
stop_service() {
|
||||
echo -e "${BLUE}正在停止结伴客后端服务...${NC}"
|
||||
pm2 stop jiebanke-backend
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${YELLOW}服务可能未在运行!${NC}"
|
||||
else
|
||||
echo -e "${GREEN}服务已停止!${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 重启服务
|
||||
restart_service() {
|
||||
echo -e "${BLUE}正在重启结伴客后端服务...${NC}"
|
||||
export NODE_ENV=$NODE_ENV
|
||||
pm2 restart ecosystem.config.js --env $NODE_ENV
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}服务重启失败!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}服务重启成功!${NC}"
|
||||
}
|
||||
|
||||
# 查看服务状态
|
||||
status_service() {
|
||||
echo -e "${BLUE}正在查看结伴客后端服务状态...${NC}"
|
||||
pm2 status jiebanke-backend
|
||||
}
|
||||
|
||||
# 查看服务日志
|
||||
logs_service() {
|
||||
echo -e "${BLUE}正在查看结伴客后端服务日志...${NC}"
|
||||
pm2 logs jiebanke-backend
|
||||
}
|
||||
|
||||
# 主函数
|
||||
handle_command() {
|
||||
# 解析命令和环境参数
|
||||
COMMAND="start"
|
||||
if [ $# -ge 1 ]; then
|
||||
case $1 in
|
||||
start|stop|restart|status|logs|install|setup|help) COMMAND=$1 ;;
|
||||
*) echo -e "${RED}未知命令:$1${NC}"; show_help; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ $# -ge 2 ]; then
|
||||
case $2 in
|
||||
production|development|test) NODE_ENV=$2 ;;
|
||||
*) echo -e "${RED}未知环境:$2${NC}"; show_help; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 执行相应的命令
|
||||
case $COMMAND in
|
||||
start)
|
||||
check_node
|
||||
check_pm2
|
||||
check_env
|
||||
check_ecosystem
|
||||
install_dependencies
|
||||
create_directories
|
||||
start_service
|
||||
;;
|
||||
stop)
|
||||
check_pm2
|
||||
stop_service
|
||||
;;
|
||||
restart)
|
||||
check_node
|
||||
check_pm2
|
||||
check_env
|
||||
install_dependencies
|
||||
restart_service
|
||||
;;
|
||||
status)
|
||||
check_pm2
|
||||
status_service
|
||||
;;
|
||||
logs)
|
||||
check_pm2
|
||||
logs_service
|
||||
;;
|
||||
install)
|
||||
check_node
|
||||
install_dependencies
|
||||
;;
|
||||
setup)
|
||||
check_pm2
|
||||
setup_autostart
|
||||
;;
|
||||
help)
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
handle_command "$@"
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 结伴客后端服务状态检查脚本
|
||||
|
||||
# 设置颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 检查服务状态
|
||||
check_status() {
|
||||
echo -e "${BLUE}正在检查结伴客后端服务状态...${NC}"
|
||||
|
||||
# 查找结伴客后端服务进程
|
||||
PROCESSES=$(ps aux | grep "node src/server.js" | grep -v grep)
|
||||
PIDS=$(echo "$PROCESSES" | awk '{print $2}')
|
||||
|
||||
if [ -z "$PIDS" ]; then
|
||||
echo -e "${RED}状态: 未运行${NC}"
|
||||
return 1
|
||||
else
|
||||
echo -e "${GREEN}状态: 运行中${NC}"
|
||||
echo -e "${BLUE}进程信息:${NC}"
|
||||
echo "$PROCESSES"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示详细信息
|
||||
show_details() {
|
||||
echo -e "${BLUE}========== 结伴客后端服务详细信息 ==========${NC}"
|
||||
|
||||
# 显示进程信息
|
||||
echo -e "${BLUE}进程信息:${NC}"
|
||||
ps aux | grep "node src/server.js" | grep -v grep || echo -e "${YELLOW}未找到相关进程${NC}"
|
||||
|
||||
# 显示端口占用情况
|
||||
echo -e "${BLUE}端口占用情况:${NC}"
|
||||
netstat -tlnp | grep :3000 || echo -e "${YELLOW}未检测到3000端口占用${NC}"
|
||||
|
||||
# 显示工作目录
|
||||
echo -e "${BLUE}当前工作目录:${NC}"
|
||||
echo "$(pwd)"
|
||||
|
||||
# 显示Node.js版本
|
||||
echo -e "${BLUE}Node.js版本:${NC}"
|
||||
node --version || echo -e "${YELLOW}未安装Node.js${NC}"
|
||||
|
||||
# 显示npm版本
|
||||
echo -e "${BLUE}npm版本:${NC}"
|
||||
npm --version || echo -e "${YELLOW}未安装npm${NC}"
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
echo "结伴客后端服务状态检查脚本"
|
||||
echo ""
|
||||
echo "使用方法:"
|
||||
echo " ./status.sh - 检查服务状态"
|
||||
echo " ./status.sh detail - 显示详细信息"
|
||||
echo " ./status.sh help - 显示帮助信息"
|
||||
}
|
||||
|
||||
# 主逻辑
|
||||
main() {
|
||||
echo -e "${GREEN}========== 结伴客后端服务状态检查 ==========${NC}"
|
||||
|
||||
# 检查参数
|
||||
case "$1" in
|
||||
"help"|"-h"|"--help")
|
||||
show_help
|
||||
;;
|
||||
"detail")
|
||||
show_details
|
||||
;;
|
||||
*)
|
||||
if check_status; then
|
||||
echo -e "${GREEN}结伴客后端服务正在正常运行${NC}"
|
||||
else
|
||||
echo -e "${RED}结伴客后端服务未运行${NC}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主逻辑
|
||||
main "$@"
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 结伴客后端服务停止脚本
|
||||
|
||||
# 设置颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 停止服务
|
||||
stop_server() {
|
||||
echo -e "${GREEN}正在停止结伴客后端服务...${NC}"
|
||||
|
||||
# 查找并停止结伴客后端服务进程
|
||||
PIDS=$(ps aux | grep "node src/server.js" | grep -v grep | awk '{print $2}')
|
||||
|
||||
if [ -z "$PIDS" ]; then
|
||||
echo -e "${YELLOW}未找到正在运行的结伴客后端服务进程${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}找到以下结伴客后端服务进程: $PIDS${NC}"
|
||||
|
||||
for PID in $PIDS; do
|
||||
echo -e "${GREEN}正在停止进程 $PID...${NC}"
|
||||
kill $PID
|
||||
|
||||
# 等待进程结束
|
||||
COUNT=0
|
||||
while kill -0 $PID 2>/dev/null; do
|
||||
sleep 1
|
||||
COUNT=$((COUNT + 1))
|
||||
if [ $COUNT -gt 10 ]; then
|
||||
echo -e "${YELLOW}进程 $PID 未能正常停止,正在强制终止...${NC}"
|
||||
kill -9 $PID
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${GREEN}进程 $PID 已停止${NC}"
|
||||
done
|
||||
|
||||
echo -e "${GREEN}结伴客后端服务已停止${NC}"
|
||||
}
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
echo "结伴客后端服务停止脚本"
|
||||
echo ""
|
||||
echo "使用方法:"
|
||||
echo " ./stop.sh - 停止所有结伴客后端服务进程"
|
||||
echo " ./stop.sh help - 显示帮助信息"
|
||||
}
|
||||
|
||||
# 主逻辑
|
||||
main() {
|
||||
echo -e "${GREEN}========== 结伴客后端服务停止脚本 ==========${NC}"
|
||||
|
||||
# 检查参数
|
||||
case "$1" in
|
||||
"help"|"-h"|"--help")
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
stop_server
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主逻辑
|
||||
main "$@"
|
||||
109
backend/sync_to_server.sh
Executable file
109
backend/sync_to_server.sh
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 结伴客后端文件同步脚本 - 同步到CentOS服务器
|
||||
# 目标服务器: 使用命令行参数或环境变量指定
|
||||
# 目标目录: /data/nodejs/jiebanke
|
||||
|
||||
# 设置颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 配置参数 - 可通过环境变量或命令行参数覆盖
|
||||
LOCAL_DIR="$(pwd)"
|
||||
REMOTE_USER=${REMOTE_USER:-"root"}
|
||||
REMOTE_HOST=${REMOTE_HOST:-"www.jiebanke.com"}
|
||||
REMOTE_DIR=${REMOTE_DIR:-"/data/nodejs/jiebanke"}
|
||||
|
||||
# 检查命令行参数
|
||||
if [ $# -ge 1 ]; then
|
||||
REMOTE_HOST=$1
|
||||
fi
|
||||
|
||||
# 检查必需参数
|
||||
if [ -z "$REMOTE_HOST" ]; then
|
||||
echo -e "${RED}错误:未指定远程服务器地址!${NC}"
|
||||
echo -e "${YELLOW}用法:$0 <remote_host> [remote_user]${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -ge 2 ]; then
|
||||
REMOTE_USER=$2
|
||||
fi
|
||||
|
||||
# 检查本地目录是否存在
|
||||
if [ ! -d "$LOCAL_DIR" ]; then
|
||||
echo -e "${RED}错误:本地目录 $LOCAL_DIR 不存在!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查rsync是否安装
|
||||
if ! command -v rsync &> /dev/null; then
|
||||
echo -e "${RED}错误:rsync未安装!请先安装rsync。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查Node.js环境
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo -e "${YELLOW}警告:本地Node.js环境未安装,但仍会继续同步文件...${NC}"
|
||||
else
|
||||
# 安装生产依赖
|
||||
echo -e "${BLUE}安装生产依赖...${NC}"
|
||||
npm install --production
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}依赖安装失败!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 确保.env文件存在
|
||||
if [ ! -f ".env" ]; then
|
||||
if [ -f ".env.example" ]; then
|
||||
echo -e "${YELLOW}未找到.env文件,正在从.env.example创建...${NC}"
|
||||
cp .env.example .env
|
||||
else
|
||||
echo -e "${RED}错误:未找到.env和.env.example文件!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 使用rsync上传文件到服务器
|
||||
echo -e "${BLUE}开始同步文件到远程服务器 ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}...${NC}"
|
||||
|
||||
# 创建排除列表
|
||||
EXCLUDE_LIST=(
|
||||
--exclude 'node_modules'
|
||||
--exclude '.git'
|
||||
--exclude '.gitignore'
|
||||
--exclude '.env.example' # 不同步示例环境文件,保留服务器上的实际配置
|
||||
--exclude 'logs'
|
||||
--exclude 'uploads'
|
||||
--exclude 'docker-compose.yml'
|
||||
--exclude 'test-*.js'
|
||||
--exclude 'README*.md'
|
||||
)
|
||||
|
||||
# 执行同步
|
||||
rsync -avz --progress --delete \
|
||||
"${EXCLUDE_LIST[@]}" \
|
||||
"$LOCAL_DIR/" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}文件同步失败!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 在服务器上创建必要的目录
|
||||
echo -e "${BLUE}在远程服务器上创建必要的目录...${NC}"
|
||||
ssh "$REMOTE_USER@$REMOTE_HOST" "mkdir -p $REMOTE_DIR/logs $REMOTE_DIR/uploads"
|
||||
|
||||
# 完成提示
|
||||
echo -e "${GREEN}文件同步完成!${NC}"
|
||||
|
||||
# 提示如何在服务器上启动服务
|
||||
echo -e "${YELLOW}请在服务器上执行以下命令以启动服务:${NC}"
|
||||
echo -e " ssh $REMOTE_USER@$REMOTE_HOST"
|
||||
echo -e " cd $REMOTE_DIR"
|
||||
echo -e " ./start_server.sh"
|
||||
@@ -1,103 +0,0 @@
|
||||
const http = require('http');
|
||||
|
||||
// 测试健康检查接口
|
||||
function testHealthCheck() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
hostname: 'webapi.jiebanke.com',
|
||||
port: 3000,
|
||||
path: '/health',
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
console.log('✅ 健康检查接口测试成功');
|
||||
console.log('状态码:', res.statusCode);
|
||||
console.log('响应:', JSON.parse(data));
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.error('❌ 健康检查接口测试失败:', error.message);
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// 测试认证接口
|
||||
function testAuthAPI() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const postData = JSON.stringify({
|
||||
username: 'testuser',
|
||||
password: 'testpass123'
|
||||
});
|
||||
|
||||
const options = {
|
||||
hostname: 'webapi.jiebanke.com',
|
||||
port: 3000,
|
||||
path: '/api/v1/auth/login',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(postData)
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
console.log('\n✅ 认证接口测试成功');
|
||||
console.log('状态码:', res.statusCode);
|
||||
try {
|
||||
const response = JSON.parse(data);
|
||||
console.log('响应:', response);
|
||||
} catch (e) {
|
||||
console.log('原始响应:', data);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.error('❌ 认证接口测试失败:', error.message);
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.write(postData);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
console.log('🚀 开始测试API接口...\n');
|
||||
|
||||
try {
|
||||
await testHealthCheck();
|
||||
await testAuthAPI();
|
||||
console.log('\n🎉 所有测试完成!');
|
||||
} catch (error) {
|
||||
console.error('\n❌ 测试失败:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此文件,则执行测试
|
||||
if (require.main === module) {
|
||||
runTests();
|
||||
}
|
||||
|
||||
module.exports = { runTests };
|
||||
@@ -1,30 +0,0 @@
|
||||
const http = require('http');
|
||||
|
||||
// 发送请求到Swagger UI
|
||||
const options = {
|
||||
hostname: 'admin.jiebanke.com',
|
||||
port: 3001,
|
||||
path: '/api-docs/',
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
console.log(`状态码: ${res.statusCode}`);
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
// 检查响应中是否包含Swagger UI的关键字
|
||||
if (chunk.toString().includes('Swagger UI')) {
|
||||
console.log('Swagger UI 已成功启动并运行');
|
||||
} else {
|
||||
console.log('收到响应,但可能不是Swagger UI页面');
|
||||
}
|
||||
// 只输出前200个字符来检查内容
|
||||
console.log('响应前200字符:', chunk.toString().substring(0, 200));
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.error('请求出错:', error.message);
|
||||
});
|
||||
|
||||
req.end();
|
||||
Reference in New Issue
Block a user