5.2 后端服务开发与部署
为什么需要后端?
前端的局限:
- ❌ 无法安全存储密钥(API Key会暴露)
- ❌ 无法处理大量数据
- ❌ 无法执行耗时任务
- ❌ 受跨域限制(CORS)
后端的作用:
- ✅ 提供 API 接口
- ✅ 处理业务逻辑
- ✅ 访问数据库
- ✅ 集成第三方服务
- ✅ 定时任务
Node.js 后端开发基础
什么是 Node.js?
简单理解:
JavaScript 原本只能在浏览器运行,Node.js 让它可以在服务器运行。
类比:
- 浏览器 = JavaScript 的游乐场
- Node.js = JavaScript 的工作场所
创建第一个 Node.js 服务器
第 1 步:初始化项目
mkdir my-api-server
cd my-api-server
npm init -y第 2 步:安装 Express 框架
npm install express第 3 步:创建 server.js
// 引入 Express
const express = require('express');
const app = express();
// 设置端口
const PORT = 3000;
// 允许解析 JSON 请求体
app.use(express.json());
// 定义第一个路由
app.get('/', (req, res) => {
res.json({
message: 'Hello World! 这是我的第一个API服务器',
timestamp: new Date().toISOString()
});
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});第 4 步:运行服务器
node server.js第 5 步:测试
打开浏览器访问 http://localhost:3000,应该看到:
{
"message": "Hello World! 这是我的第一个API服务器",
"timestamp": "2024-01-15T10:30:00.000Z"
}恭喜! 你的第一个后端服务器运行成功!🎉
RESTful API 设计
什么是 RESTful?
REST = Representational State Transfer(表现层状态转换)
核心原则:
- 使用 HTTP 方法表示操作
- 使用 URL 表示资源
- 返回标准的 HTTP 状态码
HTTP 方法对照表
| HTTP方法 | 操作 | 示例 | 说明 |
|---|---|---|---|
| GET | 获取 | GET /users | 获取用户列表 |
| POST | 创建 | POST /users | 创建新用户 |
| PUT | 更新(全部) | PUT /users/123 | 更新用户123的所有信息 |
| PATCH | 更新(部分) | PATCH /users/123 | 更新用户123的部分信息 |
| DELETE | 删除 | DELETE /users/123 | 删除用户123 |
HTTP 状态码
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 | OK | 成功 |
| 201 | Created | 创建成功 |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未授权 |
| 404 | Not Found | 资源不存在 |
| 500 | Server Error | 服务器错误 |
完整的 CRUD API 示例
【案例】Todo List API
功能:管理待办事项的增删改查
完整代码:
const express = require('express');
const app = express();
const PORT = 3000;
// 中间件
app.use(express.json());
// 模拟数据库(实际项目中应该用真实数据库)
let todos = [
{ id: 1, title: '学习 Node.js', completed: false },
{ id: 2, title: '开发 API', completed: false }
];
let nextId = 3;
// ===== 1. 获取所有待办事项 =====
app.get('/api/todos', (req, res) => {
res.json({
success: true,
data: todos
});
});
// ===== 2. 获取单个待办事项 =====
app.get('/api/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
const todo = todos.find(t => t.id === id);
if (!todo) {
return res.status(404).json({
success: false,
message: '待办事项不存在'
});
}
res.json({
success: true,
data: todo
});
});
// ===== 3. 创建新待办事项 =====
app.post('/api/todos', (req, res) => {
const { title } = req.body;
// 验证
if (!title || title.trim() === '') {
return res.status(400).json({
success: false,
message: '标题不能为空'
});
}
// 创建
const newTodo = {
id: nextId++,
title: title.trim(),
completed: false
};
todos.push(newTodo);
res.status(201).json({
success: true,
data: newTodo
});
});
// ===== 4. 更新待办事项 =====
app.patch('/api/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
const { title, completed } = req.body;
const todo = todos.find(t => t.id === id);
if (!todo) {
return res.status(404).json({
success: false,
message: '待办事项不存在'
});
}
// 更新
if (title !== undefined) {
todo.title = title.trim();
}
if (completed !== undefined) {
todo.completed = completed;
}
res.json({
success: true,
data: todo
});
});
// ===== 5. 删除待办事项 =====
app.delete('/api/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
const index = todos.findIndex(t => t.id === id);
if (index === -1) {
return res.status(404).json({
success: false,
message: '待办事项不存在'
});
}
todos.splice(index, 1);
res.json({
success: true,
message: '删除成功'
});
});
// 启动服务器
app.listen(PORT, () => {
console.log(`Todo API 服务器运行在 http://localhost:${PORT}`);
});测试 API
使用 curl 测试:
# 1. 获取所有待办
curl http://localhost:3000/api/todos
# 2. 创建新待办
curl -X POST http://localhost:3000/api/todos \
-H "Content-Type: application/json" \
-d '{"title":"学习Express"}'
# 3. 更新待办(标记完成)
curl -X PATCH http://localhost:3000/api/todos/1 \
-H "Content-Type: application/json" \
-d '{"completed":true}'
# 4. 删除待办
curl -X DELETE http://localhost:3000/api/todos/1使用浏览器插件测试:
- Thunder Client (VSCode 插件)
- Postman
- Insomnia
环境变量与配置管理
为什么需要环境变量?
问题场景:
- API Key 写在代码里 → 推送到 GitHub → 密钥泄露 ❌
- 开发环境和生产环境用不同配置 → 每次修改代码 → 容易出错 ❌
解决方案:使用 .env 文件
实践步骤
第 1 步:安装 dotenv
npm install dotenv第 2 步:创建 .env 文件
# .env
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
API_KEY=sk_test_1234567890abcdef
NODE_ENV=development第 3 步:在代码中使用
// server.js
require('dotenv').config();
const PORT = process.env.PORT || 3000;
const API_KEY = process.env.API_KEY;
console.log('API Key:', API_KEY); // 只在开发时打印,生产环境删除
app.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});第 4 步:添加到 .gitignore
# .gitignore
.env
node_modules/第 5 步:创建 .env.example
# .env.example
PORT=3000
DATABASE_URL=your_database_url
API_KEY=your_api_key
NODE_ENV=development提交到 Git:
- ✅ 提交
.env.example(模板) - ❌ 不提交
.env(实际密钥)
错误处理与日志
统一错误处理中间件
// 错误处理中间件(放在所有路由之后)
app.use((err, req, res, next) => {
console.error('错误详情:', err);
res.status(err.status || 500).json({
success: false,
message: err.message || '服务器内部错误',
// 开发环境返回错误堆栈,生产环境不返回
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
});404 处理
// 404 处理(放在所有路由之后,错误处理之前)
app.use((req, res) => {
res.status(404).json({
success: false,
message: '接口不存在'
});
});异步错误处理
// 封装异步路由处理器
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// 使用
app.get('/api/users', asyncHandler(async (req, res) => {
// 如果这里抛出错误,会自动被错误处理中间件捕获
const users = await getUsersFromDatabase();
res.json({ success: true, data: users });
}));部署到 Replit
什么是 Replit?
Replit = 在线代码编辑器 + 免费托管服务
优势:
- ✅ 免费托管
- ✅ 自动部署
- ✅ 自带数据库
- ✅ 简单易用
部署步骤
第 1 步:注册 Replit
- 访问 https://replit.com
- 使用 GitHub 账号登录
第 2 步:创建 Repl
- 点击「Create Repl」
- 选择「Node.js」模板
- 命名项目(如
my-api-server) - 点击「Create Repl」
第 3 步:上传代码
- 复制你的
server.js代码 - 粘贴到 Replit 编辑器
- 确保
package.json包含依赖
第 4 步:配置启动命令
在 .replit 文件中:
run = "node server.js"第 5 步:运行
- 点击顶部的「Run」按钮
- Replit 会自动:
- 安装依赖(
npm install) - 运行服务器
- 分配一个公网 URL
- 安装依赖(
第 6 步:获取 URL
运行成功后,右上角会显示:
https://my-api-server.username.repl.co这就是你的 API 地址!现在全世界都能访问了!
环境变量配置
在 Replit 中:
- 点击左侧「Secrets」(🔒)
- 添加环境变量:
- Key:
API_KEY - Value:
你的密钥
- Key:
- 代码中正常使用
process.env.API_KEY
Last updated on