# Node.js服务端开发

## 规则（Rules）

# Node.js服务端开发规范

## 适用对象和范围

本规范适用于所有搭建Node.js服务端应用的场景，包括Express/Koa框架搭建、中间件配置、启动管理和部署配置。

---

## 1. 变量声明规范

**规则**：能用 `const` 就用 `const`，只有确实需要重新赋值的变量才用 `let`。

- ✅ 正确：`const app = express();`、`let port = process.env.PORT || 3000;`
- ❌ 错误：`let app = express();`（不需要重新赋值却用let）

**违反后果**：滥用 `let` 降低代码可读性，无法明确标识哪些变量是只读的。

---

## 2. 命名规范

**规则**：函数使用小驼峰（camelCase），变量和参数使用小写蛇形（snake_case），常量使用全大写蛇形（SCREAMING_SNAKE_CASE）。

| 标识符类型 | 命名法 | 示例 |
|-----------|--------|------|
| 函数 | camelCase | `function getUserData(user_id) {}` |
| 变量/参数 | snake_case | `let user_name = 'xxx';` |
| 常量 | SCREAMING_SNAKE_CASE | `const MAX_RETRY_COUNT = 3;` |

- ✅ 正确：`function getUserData(user_id) { ... }`
- ❌ 错误：`function get_user_data(userId) { ... }`

**违反后果**：命名不一致导致代码可读性差。

---

## 3. 缩进规范

**规则**：统一使用2个空格缩进。

- ✅ 正确：使用2空格
- ❌ 错误：使用Tab或4空格

**违反后果**：缩进不一致导致代码结构混乱。

---

## 4. 注释规范

**规则**：函数必须使用JSDoc格式注释。

```javascript
/**
 * 获取用户数据
 * @param {number} user_id - 用户ID
 * @returns {Promise<Object>} 用户数据对象
 */
async function getUserData(user_id) {
  // ...
}
```

**违反后果**：缺少JSDoc注释导致IDE无法提供类型提示。

---

## 5. 敏感信息安全规范

**规则**：禁止将密码、密钥、token等敏感信息硬编码在代码中，必须使用环境变量。

- ✅ 正确：`const DB_PASSWORD = process.env.DB_PASSWORD;`
- ❌ 错误：`const DB_PASSWORD = '123456';`

**违反后果**：硬编码敏感信息导致代码泄露时密码一同泄露，存在严重安全风险。

---

## 6. 中间件注册顺序规范

**规则**：错误处理中间件必须注册在所有中间件和路由之后。

- ✅ 正确：
```javascript
app.use(cors());
app.use(logger());
app.use('/api', routes);
app.use(errorHandler);  // 错误处理放最后
```

- ❌ 错误：
```javascript
app.use(errorHandler);  // 错误处理放前面
app.use(cors());
app.use('/api', routes);
```

**违反后果**：错误处理中间件放前面会导致它无法捕获后续中间件的错误。

---

## 7. 目录结构规范

**规则**：服务端代码必须遵循以下目录结构。

```
./project/{项目名}/server/
├── app.js
├── config/
│   ├── index.js
│   └── db.js
├── middleware/
│   ├── auth.js
│   ├── error_handler.js
│   └── logger.js
├── routes/
├── controllers/
├── models/
├── utils/
│   └── response.js
└── package.json
```

**违反后果**：目录混乱导致代码难以维护和扩展。

## 方法（Methods）

# Node.js服务端开发方法

## 前置条件

- [ ] 已获取需求文档和架构设计文档
- [ ] 已确定服务端技术栈（Express/Koa）
- [ ] 已了解数据库类型和连接信息

## 流程概览

分析需求 → 初始化项目结构 → 编写应用入口 → 编写中间件 → 编写配置 → 编写工具函数 → 验证服务启动

## 详细步骤

### 步骤1：分析需求
分析需求文档和架构设计文档，了解服务端技术栈要求。

### 步骤2：初始化项目结构
创建服务端项目目录结构。

## 技巧（Tips）

# Node.js服务端开发技巧

## 1. 使用环境变量管理配置

**适用场景**：需要区分开发、测试、生产环境时。

**具体做法**：使用 `dotenv` 包加载 `.env` 文件，通过 `process.env` 读取配置。

**对比说明**：

| 维度 | 硬编码配置 | 环境变量 |
|------|-----------|---------|
| 安全性 | 代码泄露时配置泄露 | 配置在环境变量中 |
| 环境切换 | 需修改代码 | 切换.env文件即可 |
| 团队协作 | 每个人用不同配置需改代码 | 每人有自己的.env |

**示例**：
```javascript
// .env 文件
PORT=3000
DB_HOST=localhost
DB_PORT=27017

// config/index.js
require('dotenv').config();
module.exports = {
  port: process.env.PORT || 3000,
  db: {
    host: process.env.DB_HOST || 'localhost',
    port: process.env.DB_PORT || 27017
  }
};
```

**注意事项**：`.env` 文件不应提交到版本控制，应在 `.gitignore` 中添加。

---

## 2. 统一错误处理中间件

**适用场景**：需要统一处理所有接口的错误返回格式。

**具体做法**：编写一个错误处理中间件，放在所有中间件和路由之后。

**对比说明**：

| 维度 | 每个接口单独处理错误 | 统一错误处理 |
|------|-------------------|-------------|
| 代码量 | 每个接口都要写try/catch | 只需一个中间件 |
| 一致性 | 错误格式可能不一致 | 统一格式 |
| 维护性 | 修改格式需改所有接口 | 只需改中间件 |

**示例**：
```javascript
// error_handler.js
function errorHandler(err, req, res, next) {
  console.error(`[Error] ${req.method} ${req.path}:`, err.message);
  
  const status = err.status || 500;
  res.status(status).json({
    code: status,
    message: err.message || '服务器内部错误',
    timestamp: new Date().toISOString()
  });
}

module.exports = errorHandler;
```

**注意事项**：Express的错误处理中间件必须有4个参数 `(err, req, res, next)`。

---

## 3. 使用async中间件包装器

**适用场景**：使用 `async/await` 的路由处理器需要捕获异步错误。

**具体做法**：编写一个 `asyncHandler` 包装函数。

**对比说明**：

| 维度 | 每个路由手动try/catch | 使用asyncHandler |
|------|---------------------|-----------------|
| 代码冗余 | 每个路由都要写try/catch | 只需在定义时包裹 |
| 遗漏风险 | 容易忘记catch | 自动捕获 |

**示例**：
```javascript
// utils/async_handler.js
const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

module.exports = asyncHandler;

// routes/user_routes.js
router.get('/users', asyncHandler(async (req, res) => {
  const users = await userService.list();
  res.json({ code: 0, data: users });
}));
```

**注意事项**：Koa框架天然支持async/await错误捕获，不需要此包装器。

---

## 4. 常见问题速查

| 问题 | 原因 | 解决方案 |
|------|------|---------|
| 端口被占用 | 上次进程未关闭 | 使用 `lsof -i :端口号` 查找并kill进程 |
| CORS跨域错误 | 前端域名与后端不一致 | 配置 `cors` 中间件，设置 `origin` |
| 请求体为空 | 未配置body解析中间件 | 添加 `express.json()` 和 `express.urlencoded()` |
| 静态文件404 | 静态文件路径配置错误 | 检查 `express.static()` 的路径参数 |
| 数据库连接超时 | 连接字符串错误 | 检查 `DB_HOST`、`DB_PORT`、认证信息 |
