Skip to Content
Handbook第5章: 实战项目开发后端服务开发与部署

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 状态码

状态码含义使用场景
200OK成功
201Created创建成功
400Bad Request请求参数错误
401Unauthorized未授权
404Not Found资源不存在
500Server 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

第 2 步:创建 Repl

  1. 点击「Create Repl」
  2. 选择「Node.js」模板
  3. 命名项目(如 my-api-server
  4. 点击「Create Repl」

第 3 步:上传代码

  • 复制你的 server.js 代码
  • 粘贴到 Replit 编辑器
  • 确保 package.json 包含依赖

第 4 步:配置启动命令

.replit 文件中:

run = "node server.js"

第 5 步:运行

  • 点击顶部的「Run」按钮
  • Replit 会自动:
    1. 安装依赖(npm install
    2. 运行服务器
    3. 分配一个公网 URL

第 6 步:获取 URL

运行成功后,右上角会显示:

https://my-api-server.username.repl.co

这就是你的 API 地址!现在全世界都能访问了!

环境变量配置

在 Replit 中:

  1. 点击左侧「Secrets」(🔒)
  2. 添加环境变量:
    • Key: API_KEY
    • Value: 你的密钥
  3. 代码中正常使用 process.env.API_KEY
Last updated on