Files
autoAiWorkSys/_doc/framework_使用文档.md
张成 5d7444cd65 1
2025-11-24 13:23:42 +08:00

1416 lines
32 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.
# Node Core Framework 使用说明
## 📋 概述
`node-core-framework.js` 是一个基于 Koa2 + Sequelize + MySQL 的企业级 Node.js 后端框架,提供了完整的 MVC 架构、数据库管理、API 文档生成、权限验证等功能。
## 🚀 快速开始
### 1. 环境要求
- **Node.js**: >= 16.0.0
- **MySQL**: >= 5.7
- **Redis**: >= 5.0 (可选,用于缓存)
### 2. 安装依赖
```bash
# 安装核心依赖
npm install koa koa-body koa-router koa-static koa2-cors koa2-swagger-ui
npm install sequelize mysql2 redis jsonwebtoken dayjs swagger-jsdoc
```
### 3. 基础使用
```javascript
// app.js
const Framework = require('./dist/node-core-framework.js');
// 配置文件
const config = {
// 数据库配置
db: {
username: "your_username",
password: "your_password",
database: "your_database",
host: "localhost",
port: 3306,
dialect: "mysql",
timezone: '+08:00'
},
// Redis配置可选
redis: {
host: 'localhost',
port: 6379,
password: '',
db: 0
},
// 日志路径
logPath: './logs',
// 基础URL
baseUrl: 'http://localhost:3001',
// API路径配置
apiPaths: [
{
path: './controllers',
prefix: '/api',
authType: 'applet'
}
],
// 模型路径
modelPaths: './models',
// 允许的URL无需认证
allowUrls: [
'/api/users/login',
'/api/health',
'/api/docs'
],
// 授权文件路径
license: {
licensePath: './license.lic'
}
};
// 启动应用
async function startApp() {
try {
// 创建框架实例
const framework = await Framework.init(config);
// 启动服务器
const server = await framework.start(3001);
console.log('🎉 应用启动成功!');
console.log(`📚 API 文档: http://localhost:3001/api/docs`);
// 使用日志服务
const logsService = Framework.getServices().logsService;
logsService.log('应用启动成功', { port: 3001, time: new Date() });
} catch (error) {
console.error('❌ 启动失败:', error);
// 记录启动错误
const logsService = Framework.getServices().logsService;
logsService.error('应用启动失败', error);
}
}
startApp();
```
## 🏗️ 框架架构
### 核心组件
1. **Framework**: 主框架类,负责整体协调
2. **ModelManager**: 数据库模型管理器
3. **ServiceManager**: 服务层管理器
4. **RequestManager**: 请求处理器管理器
5. **RegistrationService**: 授权验证服务
### 目录结构
```
project/
├── dist/
│ └── node-core-framework.js # 打包后的框架文件
├── controllers/ # 控制器目录
│ ├── user_controller.js
│ ├── article_controller.js
│ └── admin/
│ ├── sys_user.js # 系统用户管理
│ └── sys_log.js # 日志管理接口
├── models/ # 数据模型目录
│ ├── user.js
│ └── article.js
├── config.js # 配置文件
├── app.js # 应用入口
└── logs/ # 日志目录
├── log_2024.01.15.log # 普通日志文件
├── logError_2024.01.15.log # 错误日志文件
└── log_2024.01.15_1.log # 分割后的日志文件
```
## 📝 详细配置说明
### 数据库配置
```javascript
const config = {
db: {
username: "root", // 数据库用户名
password: "password", // 数据库密码
database: "myapp", // 数据库名
host: "localhost", // 数据库主机
port: 3306, // 数据库端口
dialect: "mysql", // 数据库类型
timezone: '+08:00', // 时区
pool: { // 连接池配置
max: 10, // 最大连接数
min: 0, // 最小连接数
acquire: 30000, // 获取连接超时时间
idle: 10000 // 连接空闲时间
},
logging: true // 是否打印SQL日志
}
};
```
### API路径配置
```javascript
const config = {
apiPaths: [
{
path: './controllers', // 控制器目录路径
prefix: '/api', // API前缀
authType: 'applet' // 认证类型applet | admin
},
{
path: './controllers_admin', // 管理端控制器
prefix: '/admin_api', // 管理端API前缀
authType: 'admin'
}
]
};
```
### 权限配置
```javascript
const config = {
// 允许的URL无需认证
allowUrls: [
'/api/users/login', // 登录接口
'/api/users/register', // 注册接口
'/api/health', // 健康检查
'/api/docs', // API文档
'/api/swagger.json' // Swagger配置
],
// 授权文件路径
license: {
licensePath: './license.lic'
}
};
```
## 🎯 控制器开发
### 基础控制器结构
```javascript
// controllers/user_controller.js
const { models } = require('../database/db');
module.exports = {
/**
* @swagger
* /api/users:
* get:
* summary: 获取用户列表
* description: 分页获取用户列表
* tags:
* - 用户管理
* parameters:
* - in: query
* name: page
* schema:
* type: integer
* default: 1
* description: 页码
* - in: query
* name: pageSize
* schema:
* type: integer
* default: 20
* description: 每页数量
* responses:
* 200:
* description: 获取成功
*/
"GET /users": async (ctx) => {
const { user: UserModel } = models;
// 获取分页参数
const { limit, offset } = ctx.getPageSize();
// 查询用户列表
const users = await UserModel.findAndCountAll({
attributes: ['id', 'username', 'email', 'status', 'create_time'],
limit,
offset,
order: [['create_time', 'DESC']]
});
// 返回成功响应
ctx.success(users, '获取用户列表成功');
},
/**
* @swagger
* /api/users:
* post:
* summary: 创建用户
* description: 创建新用户
* tags:
* - 用户管理
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - username
* - email
* - password
* properties:
* username:
* type: string
* description: 用户名
* email:
* type: string
* format: email
* description: 邮箱
* password:
* type: string
* description: 密码
* responses:
* 200:
* description: 创建成功
*/
"POST /users": async (ctx) => {
const { user: UserModel } = models;
const { username, email, password } = ctx.getBody();
// 参数验证
if (!username || !email || !password) {
return ctx.fail('用户名、邮箱和密码不能为空');
}
// 检查邮箱是否已存在
const existingUser = await UserModel.findOne({ where: { email } });
if (existingUser) {
return ctx.fail('邮箱已存在');
}
// 创建用户
const newUser = await UserModel.create({
username,
email,
password,
status: 1
});
ctx.success({
id: newUser.id,
username: newUser.username,
email: newUser.email
}, '用户创建成功');
}
};
```
### 控制器方法说明
#### 请求方法格式
框架支持 **GET****POST** 两种请求方法,**推荐统一使用 POST 请求**
- `"POST /users"`: POST 请求(推荐)
- 参数通过请求体传递:`{ id: 123, username: "张三", pageOption: { page: 1, pageSize: 20 } }`
- 适用场景:所有接口(查询、创建、更新、删除等)
- 优点:参数传递统一、支持复杂数据结构、更安全
- `"GET /users"`: GET 请求(不推荐)
- 参数通过查询字符串传递:`?id=123&status=1`
- 仅在简单查询场景下使用
#### 上下文方法
```javascript
// 获取请求体数据
const body = ctx.getBody();
// 获取查询参数
const query = ctx.getQuery();
// 获取分页参数(从前端的 pageOption 中获取 page 和 pageSize
// 前端发送格式:{ pageOption: { page: 1, pageSize: 20 } }
// 返回值:{ limit: 20, offset: 0 }
const { limit, offset } = ctx.getPageSize();
// 成功响应
ctx.success(data, message);
// 失败响应
ctx.fail(message, code);
```
## 🗄️ 数据模型开发
### 模型定义
```javascript
// models/user.js
const Sequelize = require('sequelize');
module.exports = (db) => {
return db.define("user", {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
comment: "用户ID"
},
username: {
type: Sequelize.STRING(50),
allowNull: false,
comment: "用户名"
},
email: {
type: Sequelize.STRING(100),
allowNull: false,
unique: true,
comment: "邮箱"
},
password: {
type: Sequelize.STRING(255),
allowNull: false,
comment: "密码"
},
avatar: {
type: Sequelize.STRING(255),
comment: "头像URL"
},
status: {
type: Sequelize.INTEGER,
defaultValue: 1,
comment: "状态0-禁用1-启用"
}
});
};
```
### 模型关联
```javascript
// 在启动文件中定义关联关系
const businessAssociations = (models) => {
// 用户和文章的一对多关系
if (models.user && models.article) {
models.user.hasMany(models.article, {
foreignKey: 'author_id',
as: 'articles',
constraints: false // 不创建外键约束
});
models.article.belongsTo(models.user, {
foreignKey: 'author_id',
as: 'author',
constraints: false
});
}
};
// 在框架初始化时传入
const framework = await Framework.init({
// ... 其他配置
businessAssociations: businessAssociations
});
```
## 🔐 权限验证
### Token 验证
框架支持两种认证类型:
- `applet`: 小程序端认证
- `admin`: 管理端认证
### 认证中间件
```javascript
// 在控制器中获取当前用户
"POST /profile": async (ctx) => {
// 获取当前登录用户信息
const currentUser = ctx.state.user;
if (!currentUser) {
return ctx.fail('未登录', 401);
}
ctx.success(currentUser, '获取用户信息成功');
}
```
## 📊 API 文档
### Swagger 配置
框架自动生成 API 文档,访问地址:`http://localhost:3001/api/docs`
### 自定义 Schema
```javascript
const config = {
customSchemas: {
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "用户ID"
},
"username": {
"type": "string",
"description": "用户名"
},
"email": {
"type": "string",
"format": "email",
"description": "邮箱"
}
}
}
}
};
```
## 🚀 部署配置
### 生产环境配置
```javascript
const config = {
env: 'production',
db: {
// 生产数据库配置
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
dialect: "mysql",
logging: false // 生产环境关闭SQL日志
},
redis: {
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD
},
server: {
port: process.env.PORT || 3001,
host: '0.0.0.0'
}
};
```
### PM2 部署
```javascript
// ecosystem.config.js
module.exports = {
apps: [{
name: 'myapp',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3001
}
}]
};
```
```bash
# 启动应用
pm2 start ecosystem.config.js
# 查看状态
pm2 status
# 查看日志
pm2 logs myapp
```
## 🔧 常用功能
### 日志服务
框架内置了完整的日志服务,支持普通日志、错误日志和请求日志记录。
#### 获取日志服务
```javascript
// 在控制器中获取日志服务
const Framework = require('./dist/node-core-framework.js');
const logsService = Framework.getServices().logsService;
#### 基本日志记录
```javascript
// 普通日志
logsService.log('用户登录成功', { userId: 123, username: 'admin' });
logsService.log('数据更新完成', '用户信息已更新');
// 错误日志
try {
// 业务逻辑
throw new Error('数据库连接失败');
} catch (error) {
logsService.error('数据库操作失败', error);
}
// 上下文错误日志(包含请求信息)
logsService.ctxError(error, ctx);
```
#### 日志文件管理
```javascript
// 日志文件自动管理
// - 按日期分割log_2024.01.15.log
// - 错误日志logError_2024.01.15.log
// - 文件大小超过5MB自动分割log_2024.01.15_1.log
// - 自动创建日志目录
```
#### 日志API接口
框架提供了日志管理的API接口
```javascript
// 获取所有日志文件列表
GET /admin_api/sys_log/all
// 查看日志文件内容
GET /admin_api/sys_log/detail?title=log_2024.01.15.log
// 删除指定日志文件
GET /admin_api/sys_log/delete?title=log_2024.01.15.log
// 删除所有日志文件
GET /admin_api/sys_log/delete_all
```
#### 日志配置
```javascript
const config = {
// 日志目录配置
logPath: './logs', // 相对路径,基于项目根目录
// 其他配置...
};
// 日志目录结构
// project/
// ├── logs/
// │ ├── log_2024.01.15.log # 普通日志
// │ ├── logError_2024.01.15.log # 错误日志
// │ └── log_2024.01.15_1.log # 分割后的日志
```
#### 实际使用示例
```javascript
// controller/user.js
const Framework = require('../framework');
const logsService = Framework.getServices().logsService;
module.exports = {
"POST /login": async (ctx) => {
try {
const { username, password } = ctx.getBody();
// 记录登录尝试
logsService.log('用户登录尝试', { username, ip: ctx.ip });
// 验证用户
const user = await UserModel.findOne({ where: { username } });
if (!user) {
logsService.log('登录失败:用户不存在', { username });
return ctx.fail('用户名或密码错误');
}
// 验证密码
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
logsService.log('登录失败:密码错误', { username });
return ctx.fail('用户名或密码错误');
}
// 登录成功
logsService.log('用户登录成功', {
userId: user.id,
username: user.username,
ip: ctx.ip
});
ctx.success({ token: generateToken(user) }, '登录成功');
} catch (error) {
// 记录系统错误
logsService.ctxError(error, ctx);
ctx.fail('登录失败,请稍后重试');
}
}
};
```
### Token服务
框架内置了JWT Token服务支持Token生成、验证、解析和微信数据解密。
#### 获取Token服务
```javascript
// 在控制器中获取Token服务
const Framework = require('./dist/node-core-framework.js');
const tokenService = Framework.getServices().tokenService;
// 或者通过框架实例获取
const framework = await Framework.init(config);
const tokenService = Framework.getServices().tokenService;
```
#### 基本Token操作
```javascript
// 创建Token
const userInfo = { id: 123, username: 'admin', role: 'admin' };
const token = tokenService.create(userInfo);
// 解析Token获取用户信息
const userData = tokenService.parse(token);
console.log(userData); // { id: 123, username: 'admin', role: 'admin' }
// 验证Token检查是否有效
const isValid = tokenService.verify(token);
console.log(isValid); // true 或 false
```
#### 微信数据解密
```javascript
// 解密微信小程序数据
const encryptedData = 'encrypted_data_from_wechat';
const sessionKey = 'session_key_from_wechat';
const iv = 'iv_from_wechat';
const decryptedData = tokenService.decryptWxData(encryptedData, sessionKey, iv);
console.log(decryptedData); // 解密后的用户信息
```
#### MD5加密
```javascript
// MD5加密
const password = '123456';
const encryptedPassword = tokenService.getMd5(password);
console.log(encryptedPassword); // e10adc3949ba59abbe56e057f20f883e
```
#### 实际使用示例
```javascript
// controller/auth.js
const Framework = require('../framework');
const tokenService = Framework.getServices().tokenService;
module.exports = {
"POST /login": async (ctx) => {
try {
const { username, password } = ctx.getBody();
// 验证用户
const user = await UserModel.findOne({ where: { username } });
if (!user) {
return ctx.fail('用户不存在');
}
// 验证密码
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
return ctx.fail('密码错误');
}
// 生成Token
const userInfo = {
id: user.id,
username: user.username,
role: user.role
};
const token = tokenService.create(userInfo);
ctx.success({ token, user: userInfo }, '登录成功');
} catch (error) {
ctx.fail('登录失败');
}
},
"POST /verify": async (ctx) => {
const { token } = ctx.getBody();
if (!token) {
return ctx.fail('缺少Token');
}
const userData = tokenService.parse(token);
if (!userData) {
return ctx.fail('Token无效');
}
ctx.success(userData, 'Token验证成功');
}
};
```
### Redis服务
框架内置了Redis缓存服务支持数据缓存、分布式锁等功能。
#### 获取Redis服务
```javascript
// 在控制器中获取Redis服务
const Framework = require('./dist/node-core-framework.js');
const redisService = Framework.getServices().redisService;
// 或者通过框架实例获取
const framework = await Framework.init(config);
const redisService = Framework.getServices().redisService;
```
#### 基本缓存操作
```javascript
// 设置缓存默认12小时过期
await redisService.set('user:123', JSON.stringify({ name: '张三', age: 25 }));
// 设置缓存(自定义过期时间,单位:秒)
await redisService.set('session:abc', 'session_data', 3600); // 1小时
// 获取缓存
const userData = await redisService.get('user:123');
console.log(JSON.parse(userData)); // { name: '张三', age: 25 }
// 删除缓存
await redisService.del('user:123');
```
#### 原子操作
```javascript
// 原子设置仅当key不存在时设置
const success = await redisService.setIfAbsent('lock:order:123', 'locked', 300);
if (success) {
console.log('获取锁成功');
// 执行业务逻辑
await redisService.del('lock:order:123'); // 释放锁
} else {
console.log('获取锁失败,资源被占用');
}
```
#### 连接状态管理
```javascript
// 检查Redis连接状态
const isConnected = redisService.isConnected();
console.log('Redis连接状态:', isConnected);
// 手动重连
redisService.reconnect();
// 关闭连接
redisService.close();
```
#### 实际使用示例
```javascript
// controller/cache.js
const Framework = require('../framework');
const redisService = Framework.getServices().redisService;
module.exports = {
"POST /cache/user/detail": async (ctx) => {
const { id } = ctx.getBody(); // 从请求体获取 id
if (!id) {
return ctx.fail('用户ID不能为空');
}
const cacheKey = `user:${id}`;
try {
// 先尝试从缓存获取
let userData = await redisService.get(cacheKey);
if (userData) {
// 缓存命中
console.log('从缓存获取用户数据');
return ctx.success(JSON.parse(userData));
}
// 缓存未命中,从数据库获取
const user = await UserModel.findByPk(id);
if (!user) {
return ctx.fail('用户不存在');
}
// 存入缓存1小时过期
await redisService.set(cacheKey, JSON.stringify(user.toJSON()), 3600);
ctx.success(user);
} catch (error) {
ctx.fail('获取用户信息失败');
}
},
"POST /cache/clear": async (ctx) => {
const { pattern } = ctx.getBody();
// 清除指定模式的缓存
// 注意:这里需要根据实际需求实现模式匹配删除
await redisService.del(pattern);
ctx.success(null, '缓存清除成功');
}
};
```
### Swagger服务
框架内置了Swagger API文档服务支持自动生成API文档和Schema。
#### 获取Swagger服务
```javascript
// 在控制器中获取Swagger服务
const Framework = require('./dist/node-core-framework.js');
const swaggerService = Framework.getServices().createSwaggerService();
// 或者通过框架实例获取
const framework = await Framework.init(config);
const swaggerService = Framework.getServices().createSwaggerService();
```
#### 生成API文档
```javascript
// 生成Swagger规范
const swaggerSpec = swaggerService.generateSpecs(req, res);
// 获取Swagger配置
const swaggerConfig = swaggerService.generateSwaggerConfig(req, res);
// 获取Swagger选项
const swaggerOptions = swaggerService.getSwaggerOptions();
```
#### 安全配置管理
```javascript
// 获取当前安全配置
const securityConfig = swaggerService.getCurrentSecurityConfig(req, res);
// 更新安全配置
const newConfig = [
{ 'admin-token': [] },
{ 'applet-token': [] }
];
const result = swaggerService.updateSecurityConfig(req, res, newConfig);
// 清除安全配置
swaggerService.clearSecurityConfigCookie(res);
```
#### 实际使用示例
```javascript
// controller/docs.js
const Framework = require('../framework');
module.exports = {
"POST /api-docs": async (ctx) => {
const swaggerService = Framework.getServices().createSwaggerService();
// 生成Swagger规范
const swaggerSpec = swaggerService.generateSpecs(ctx.request, ctx.response);
ctx.response.type = 'application/json';
ctx.response.body = swaggerSpec;
},
"POST /swagger-ui": async (ctx) => {
// 返回Swagger UI页面
const swaggerUIManager = Framework.getSwaggerUIManager();
const html = swaggerUIManager.getSwaggerUIHTML();
ctx.response.type = 'text/html';
ctx.response.body = html;
}
};
```
### 平台项目服务
框架内置了平台项目服务,支持与外部平台的交互。
#### 获取平台项目服务
```javascript
// 在控制器中获取平台项目服务
const Framework = require('./dist/node-core-framework.js');
const platformService = Framework.getServices().platformProjectService;
// 或者通过框架实例获取
const framework = await Framework.init(config);
const platformService = Framework.getServices().platformProjectService;
```
#### 基本平台操作
```javascript
// 获取所有模型
const models = await platformService.modelAll();
// 生成表单
const formData = await platformService.formGenerate({ id: 'form_id' });
// 创建表单
const createResult = await platformService.createForm({
name: '用户表单',
fields: ['name', 'email', 'phone']
});
// 更新表单
const updateResult = await platformService.updateForm({
id: 'form_id',
name: '更新后的表单'
});
// 删除表单
const deleteResult = await platformService.delteForm({ id: 'form_id' });
// 重新生成模型
const modelResult = await platformService.modelGenerate({ id: 'model_id' });
```
#### 文件下载
```javascript
// 下载平台文件
const downloadResult = await platformService.downloadPlatformFile('/path/to/file');
```
#### 实际使用示例
```javascript
// controller/platform.js
const Framework = require('../framework');
const platformService = Framework.getServices().platformProjectService;
module.exports = {
"POST /platform/models": async (ctx) => {
try {
const models = await platformService.modelAll();
ctx.success(models);
} catch (error) {
ctx.fail('获取模型列表失败');
}
},
"POST /platform/form": async (ctx) => {
try {
const formData = ctx.getBody();
const result = await platformService.createForm(formData);
ctx.success(result, '表单创建成功');
} catch (error) {
ctx.fail('表单创建失败');
}
}
};
```
### HTTP服务
框架内置了HTTP请求服务支持各种HTTP请求方法。
#### 获取HTTP服务
```javascript
// 直接引入HTTP服务
const { postPlatformUrl, downloadPlatformFile, post, get } = require('./services/http');
```
#### 基本HTTP操作
```javascript
// GET请求
const getData = await get('https://api.example.com/users', { page: 1, limit: 10 });
// POST请求
const postData = await post('https://api.example.com/users', {
name: '张三',
email: 'zhangsan@example.com'
});
// POST表单数据
const formData = await postFormData('https://api.example.com/upload', {
file: 'file_content',
name: 'filename.jpg'
});
```
#### 平台API调用
```javascript
// 调用平台API
const platformData = await postPlatformUrl('/form/generate', { id: 'form_id' });
// 下载平台文件
await downloadPlatformFile('/path/to/file', './local/path/file');
```
#### 实际使用示例
```javascript
// controller/external.js
const { post, get } = require('../services/http');
module.exports = {
"POST /external/users": async (ctx) => {
try {
// 调用外部API
const users = await get('https://jsonplaceholder.typicode.com/users');
ctx.success(users);
} catch (error) {
ctx.fail('获取外部数据失败');
}
},
"POST /external/sync": async (ctx) => {
try {
const { data } = ctx.getBody();
// 同步数据到外部系统
const result = await post('https://api.external.com/sync', data);
ctx.success(result, '数据同步成功');
} catch (error) {
ctx.fail('数据同步失败');
}
}
};
```
### 分页查询
框架提供了 `ctx.getPageSize()` 方法来获取分页参数。
**前端发送格式**:
```javascript
// 方式1: 通过 POST 请求体发送
{
pageOption: {
page: 1, // 页码从1开始
pageSize: 20 // 每页数量
}
}
// 方式2: 通过 GET 查询参数发送
// GET /api/users?pageOption[page]=1&pageOption[pageSize]=20
```
**后端使用示例**:
```javascript
"POST /users/list": async (ctx) => {
// ctx.getPageSize() 从前端的 pageOption 中获取 page 和 pageSize
// 返回值:{ limit: 20, offset: 0 }
// limit: 每页数量 (pageSize)
// offset: 跳过的记录数 ((page - 1) * pageSize)
const { limit, offset } = ctx.getPageSize();
const { username, status } = ctx.getBody(); // 从请求体获取查询条件
// 构建查询条件
const where = {};
if (username) {
where.username = { [Op.like]: `%${username}%` };
}
if (status !== undefined) {
where.status = status;
}
const users = await UserModel.findAndCountAll({
where,
limit,
offset,
order: [['create_time', 'DESC']]
});
ctx.success(users, '获取用户列表成功');
}
```
### 文件上传
```javascript
"POST /upload": async (ctx) => {
const file = ctx.request.files.file;
if (!file) {
return ctx.fail('请选择文件');
}
// 处理文件上传逻辑
const fileName = `${Date.now()}_${file.name}`;
const filePath = `./upload/${fileName}`;
// 保存文件
const fs = require('fs');
fs.writeFileSync(filePath, file.buffer);
ctx.success({
fileName,
filePath,
size: file.size
}, '文件上传成功');
}
```
### 错误处理
```javascript
// 全局错误处理
framework.app.on('error', (err, ctx) => {
console.error('服务器错误:', err);
// 记录错误日志
const logger = require('./services/logs');
logger.error('服务器错误', {
error: err.message,
stack: err.stack,
url: ctx.url,
method: ctx.method
});
});
```
## 📝 最佳实践
### 1. 控制器设计
```javascript
// 好的实践:统一使用 POST 请求,清晰的路由命名
module.exports = {
"POST /users/list": getUserList, // 获取用户列表
"POST /users/detail": getUserDetail, // 获取用户详情
"POST /users/create": createUser, // 创建用户
"POST /users/update": updateUser, // 更新用户
"POST /users/delete": deleteUser // 删除用户
};
// 查询列表示例:支持分页和条件查询
async function getUserList(ctx) {
const { limit, offset } = ctx.getPageSize(); // 从 pageOption 获取分页参数
const { username, status } = ctx.getBody(); // 从请求体获取查询条件
// 构建查询条件
const where = {};
if (username) {
where.username = { [Op.like]: `%${username}%` };
}
if (status !== undefined) {
where.status = status;
}
const users = await UserModel.findAndCountAll({
where,
limit,
offset,
order: [['create_time', 'DESC']]
});
ctx.success(users, '获取用户列表成功');
}
// 查询详情示例
async function getUserDetail(ctx) {
const { id } = ctx.getBody(); // 从请求体获取 id
if (!id) {
return ctx.fail('用户ID不能为空');
}
const user = await UserModel.findByPk(id);
if (!user) {
return ctx.fail('用户不存在');
}
ctx.success(user, '获取成功');
}
// 创建示例
async function createUser(ctx) {
const { username, email, password } = ctx.getBody();
if (!username || !email || !password) {
return ctx.fail('用户名、邮箱和密码不能为空');
}
const newUser = await UserModel.create({ username, email, password });
ctx.success(newUser, '创建成功');
}
// 更新示例
async function updateUser(ctx) {
const { id, username, email } = ctx.getBody();
if (!id) {
return ctx.fail('用户ID不能为空');
}
await UserModel.update({ username, email }, { where: { id } });
ctx.success(null, '更新成功');
}
// 删除示例
async function deleteUser(ctx) {
const { id } = ctx.getBody();
if (!id) {
return ctx.fail('用户ID不能为空');
}
await UserModel.destroy({ where: { id } });
ctx.success(null, '删除成功');
}
```
### 2. 数据验证
```javascript
// 好的实践:参数验证
"POST /users": async (ctx) => {
const { username, email, password } = ctx.getBody();
// 参数验证
if (!username || !email || !password) {
return ctx.fail('用户名、邮箱和密码不能为空');
}
// 邮箱格式验证
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return ctx.fail('邮箱格式不正确');
}
// 业务逻辑...
}
```
### 3. 错误处理
```javascript
// 好的实践:统一的错误处理
"POST /users": async (ctx) => {
try {
const { username, email, password } = ctx.getBody();
// 验证参数
validateUserInput({ username, email, password });
// 检查用户是否存在
await checkUserExists(email);
// 创建用户
const user = await createUser({ username, email, password });
ctx.success(user, '用户创建成功');
} catch (error) {
// 统一错误处理
if (error.code === 'VALIDATION_ERROR') {
return ctx.fail(error.message, 400);
}
if (error.code === 'USER_EXISTS') {
return ctx.fail(error.message, 409);
}
// 未知错误
console.error('创建用户失败:', error);
ctx.fail('服务器内部错误', 500);
}
}
```
## ❓ 常见问题
### Q1: 数据库连接失败
**解决方案**:
1. 检查数据库服务是否启动
2. 验证配置文件中的数据库连接信息
3. 确认数据库用户权限
### Q2: 端口被占用
**解决方案**:
```bash
# 查看端口占用
netstat -ano | findstr :3001
# 终止进程
taskkill /PID <进程ID> /F
```
### Q3: 模块找不到
**解决方案**:
```bash
# 重新安装依赖
npm install
# 清除缓存
npm cache clean --force
```
### Q4: 权限验证失败
**解决方案**:
1. 检查请求头中的 token
2. 确认 token 格式正确
3. 验证 token 是否过期
## 📚 更多资源
- [框架源码](https://github.com/your-repo/node-core-framework)
- [API 文档](http://localhost:3001/api/docs)
- [示例项目](./examples/)
---
**🎉 恭喜!你已经掌握了 Node Core Framework 的基本使用方法!**
如有问题,请查看项目文档或提交 Issue。