前置要求:JavaScript基础
学习时长:约2-3天(每天4小时)
Node.js版本:20+(LTS)
适用场景:后端API、实时应用、CLI工具、微服务
一、Node.js 是什么?
Node.js 是基于 Chrome V8 引擎的 JavaScript 运行时,让 JavaScript 可以在服务器端运行。
| 特点 | 说明 |
|---|---|
| 语言 | JavaScript(前端开发者无缝切换) |
| 性能 | 非阻塞I/O,高并发处理能力强 |
| 生态 | npm是全球最大的包管理器 |
| 适用场景 | REST API、实时应用、CLI工具、BFF层 |
二、安装与配置
# macOS
brew install node
# Ubuntu
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install nodejs
# Windows
# 下载:https://nodejs.org/
# 验证
node -v
npm -v
# 包管理器(推荐pnpm)
npm install -g pnpm
pnpm -v
三、基础语法
// ====================
// 模块系统
// ====================
// ES Modules(推荐)
import fs from 'fs'
import path from 'path'
import { readFile, writeFile } from 'fs/promises'
// CommonJS(传统)
const fs = require('fs')
const path = require('path')
// ====================
// 内置模块
// ====================
import fs from 'fs/promises'
import path from 'path'
import os from 'os'
import crypto from 'crypto'
// 文件操作
const content = await fs.readFile('data.txt', 'utf-8')
await fs.writeFile('output.txt', 'Hello, Node.js!')
await fs.mkdir('data', { recursive: true })
// 路径操作
const fullPath = path.join(__dirname, 'data', 'file.txt')
const ext = path.extname('file.txt') // '.txt'
const basename = path.basename('/path/to/file.txt') // 'file.txt'
// 系统信息
console.log(os.platform()) // 'win32' / 'darwin' / 'linux'
console.log(os.cpus().length) // CPU核心数
console.log(os.totalmem()) // 总内存
// 加密
const hash = crypto.createHash('sha256').update('password').digest('hex')
const uuid = crypto.randomUUID()
// ====================
// 环境变量
// ====================
const port = process.env.PORT || 3000
const nodeEnv = process.env.NODE_ENV || 'development'
四、Express 框架
# 安装
pnpm add express
# 创建项目
mkdir my-api && cd my-api
pnpm init
pnpm add express cors helmet morgan
pnpm add -D nodemon
// app.js
import express from 'express'
import cors from 'cors'
import helmet from 'helmet'
import morgan from 'morgan'
const app = express()
const PORT = process.env.PORT || 3000
// 中间件
app.use(helmet()) // 安全头
app.use(cors()) // 跨域
app.use(morgan('dev')) // 日志
app.use(express.json()) // 解析JSON
app.use(express.urlencoded({ extended: true })) // 解析表单
// 模拟数据
let users = [
{ id: 1, username: '张三', email: 'zhangsan@example.com', age: 25 },
{ id: 2, username: '李四', email: 'lisi@example.com', age: 30 }
]
let nextId = 3
// ====================
// 路由
// ====================
// GET - 用户列表
app.get('/api/users', (req, res) => {
const { keyword, page = 1, size = 10 } = req.query
let filtered = users
if (keyword) {
filtered = users.filter(u =>
u.username.includes(keyword) || u.email.includes(keyword)
)
}
const start = (page - 1) * size
const paginated = filtered.slice(start, start + Number(size))
res.json({
code: 200,
data: {
items: paginated,
total: filtered.length,
page: Number(page),
size: Number(size)
}
})
})
// GET - 单个用户
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === Number(req.params.id))
if (!user) {
return res.status(404).json({ code: 404, message: '用户不存在' })
}
res.json({ code: 200, data: user })
})
// POST - 创建用户
app.post('/api/users', (req, res) => {
const { username, email, age } = req.body
// 验证
if (!username || !email) {
return res.status(422).json({ code: 422, message: '用户名和邮箱不能为空' })
}
// 检查重复
if (users.some(u => u.username === username)) {
return res.status(409).json({ code: 409, message: '用户名已存在' })
}
const user = { id: nextId++, username, email, age }
users.push(user)
res.status(201).json({ code: 201, message: '创建成功', data: user })
})
// PUT - 更新用户
app.put('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === Number(req.params.id))
if (index === -1) {
return res.status(404).json({ code: 404, message: '用户不存在' })
}
users[index] = { ...users[index], ...req.body }
res.json({ code: 200, message: '更新成功', data: users[index] })
})
// DELETE - 删除用户
app.delete('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === Number(req.params.id))
if (index === -1) {
return res.status(404).json({ code: 404, message: '用户不存在' })
}
users.splice(index, 1)
res.json({ code: 200, message: '删除成功' })
})
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).json({ code: 500, message: '服务器内部错误' })
})
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`)
})
// package.json
{
"type": "module",
"scripts": {
"dev": "nodemon app.js",
"start": "node app.js"
}
}
五、中间件模式
// ====================
// 自定义中间件
// ====================
// 日志中间件
const logger = (req, res, next) => {
const start = Date.now()
res.on('finish', () => {
const duration = Date.now() - start
console.log(`${req.method} ${req.url} ${res.statusCode} ${duration}ms`)
})
next()
}
// 认证中间件
const auth = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1]
if (!token) {
return res.status(401).json({ code: 401, message: '未登录' })
}
try {
const decoded = jwt.verify(token, SECRET_KEY)
req.user = decoded
next()
} catch (err) {
res.status(401).json({ code: 401, message: 'token无效' })
}
}
// 验证中间件
const validateUser = (req, res, next) => {
const { username, email } = req.body
const errors = []
if (!username || username.length < 3) {
errors.push('用户名至少3个字符')
}
if (!email || !email.includes('@')) {
errors.push('邮箱格式不正确')
}
if (errors.length > 0) {
return res.status(422).json({ code: 422, message: '验证失败', errors })
}
next()
}
// 使用中间件
app.post('/api/users', validateUser, (req, res) => {
// 处理请求
})
app.get('/api/profile', auth, (req, res) => {
res.json({ user: req.user })
})
六、数据库操作(Prisma ORM)
# 安装Prisma
pnpm add prisma @prisma/client
npx prisma init
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(50)
email String @unique @db.VarChar(100)
age Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(200)
content String @db.Text
author User @relation(fields: [authorId], references: [id])
authorId Int
createdAt DateTime @default(now())
}
# 数据库迁移
npx prisma migrate dev --name init
npx prisma generate
// 使用Prisma
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// 创建
const user = await prisma.user.create({
data: {
username: '张三',
email: 'zhangsan@example.com',
age: 25
}
})
// 查询
const users = await prisma.user.findMany({
where: { isActive: true },
include: { posts: true },
orderBy: { createdAt: 'desc' },
skip: 0,
take: 10
})
// 更新
const updated = await prisma.user.update({
where: { id: 1 },
data: { age: 26 }
})
// 删除
await prisma.user.delete({ where: { id: 1 } })
七、项目结构
my-api/
├── src/
│ ├── controllers/ # 控制器
│ │ └── userController.js
│ ├── middleware/ # 中间件
│ │ ├── auth.js
│ │ └── validate.js
│ ├── routes/ # 路由
│ │ ├── index.js
│ │ └── userRoutes.js
│ ├── services/ # 业务逻辑
│ │ └── userService.js
│ ├── utils/ # 工具函数
│ │ └── response.js
│ └── app.js # Express应用
├── prisma/
│ └── schema.prisma # 数据库模型
├── .env # 环境变量
├── package.json
└── README.md
八、常用npm包
| 包名 | 用途 |
|---|---|
| express | Web框架 |
| cors | 跨域处理 |
| helmet | 安全头 |
| morgan | HTTP日志 |
| jsonwebtoken | JWT认证 |
| bcryptjs | 密码加密 |
| multer | 文件上传 |
| dotenv | 环境变量 |
| prisma | ORM |
| zod | 数据验证 |
| winston | 应用日志 |
| bull | 消息队列 |
| ioredis | Redis客户端 |
学习建议
- 先掌握Express基础,理解路由和中间件
- 学习Prisma或TypeORM,数据库操作是核心
- 理解异步编程,async/await是必须掌握的
- 学会项目分层,controller/service/repository
- 做一个完整项目,如博客API或电商API