Express 框架
Express 是 Node.js 最流行的 Web 框架,基于 http 模块封装,提供路由、中间件等强大功能。
安装与脚手架
手动创建
bash
npm init -y
npm install expressnpm init -y
npm install express使用生成器
bash
npx express-generator
# 或全局安装
npm install -g express-generator
express myapp
cd myapp && npm installnpx express-generator
# 或全局安装
npm install -g express-generator
express myapp
cd myapp && npm install生成器创建的目录结构:
myapp/
├── bin/ # HTTP 服务启动文件
│ └── www
├── public/ # 静态文件
├── routes/ # 路由模块
│ ├── index.js
│ └── users.js
├── views/ # 视图模板
├── app.js # 主程序
└── package.jsonmyapp/
├── bin/ # HTTP 服务启动文件
│ └── www
├── public/ # 静态文件
├── routes/ # 路由模块
│ ├── index.js
│ └── users.js
├── views/ # 视图模板
├── app.js # 主程序
└── package.json基本用法
js
const express = require('express')
const app = express()
const port = 3000
// 路由
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`)
})const express = require('express')
const app = express()
const port = 3000
// 路由
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`)
})静态服务
使用 express.static() 中间件提供静态文件服务:
js
const path = require('path')
app.use(express.static(path.join(__dirname, 'public')))
// public 目录下的文件可直接通过 URL 访问const path = require('path')
app.use(express.static(path.join(__dirname, 'public')))
// public 目录下的文件可直接通过 URL 访问API 服务
请求方法
js
app.get('/api/users', (req, res) => {
res.json({ data: [{ name: '张三' }] })
})
app.post('/api/users', (req, res) => {
res.json({ success: true })
})
app.put('/api/users/:id', (req, res) => {
res.json({ success: true })
})
app.delete('/api/users/:id', (req, res) => {
res.json({ success: true })
})app.get('/api/users', (req, res) => {
res.json({ data: [{ name: '张三' }] })
})
app.post('/api/users', (req, res) => {
res.json({ success: true })
})
app.put('/api/users/:id', (req, res) => {
res.json({ success: true })
})
app.delete('/api/users/:id', (req, res) => {
res.json({ success: true })
})接收参数
js
// 查询字符串参数 — GET /api/users?page=1
req.query.page // '1'
// 路径参数 — GET /api/users/123
req.params.id // '123'
// POST 请求体(需配置中间件)
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
req.body // 请求体数据// 查询字符串参数 — GET /api/users?page=1
req.query.page // '1'
// 路径参数 — GET /api/users/123
req.params.id // '123'
// POST 请求体(需配置中间件)
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
req.body // 请求体数据响应方法
js
res.send('文本') // 发送文本
res.json({ key: 'value' }) // 发送 JSON
res.sendFile(path) // 发送文件
res.status(404).send('Not Found') // 设置状态码res.send('文本') // 发送文本
res.json({ key: 'value' }) // 发送 JSON
res.sendFile(path) // 发送文件
res.status(404).send('Not Found') // 设置状态码路由模块化
使用 express.Router() 实现路由拆分:
js
// routes/users.js
const express = require('express')
const router = express.Router()
router.get('/list', (req, res) => {
res.json([{ name: '张三' }])
})
router.post('/create', (req, res) => {
res.json({ success: true })
})
module.exports = router// routes/users.js
const express = require('express')
const router = express.Router()
router.get('/list', (req, res) => {
res.json([{ name: '张三' }])
})
router.post('/create', (req, res) => {
res.json({ success: true })
})
module.exports = routerjs
// app.js
const userRoutes = require('./routes/users')
app.use('/api/users', userRoutes)
// 访问:GET /api/users/list// app.js
const userRoutes = require('./routes/users')
app.use('/api/users', userRoutes)
// 访问:GET /api/users/list中间件
中间件是 Express 的核心机制,按顺序依次处理请求。
自定义中间件
js
// 全局中间件(所有请求都会经过)
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`)
next() // 交出控制权,继续下一个中间件
})
// 路由级中间件
app.use('/api', (req, res, next) => {
console.log('API 请求')
next()
})
// 错误处理中间件(4个参数)
app.use((err, req, res, next) => {
console.error('错误:', err.message)
res.status(500).send('服务器错误')
})// 全局中间件(所有请求都会经过)
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`)
next() // 交出控制权,继续下一个中间件
})
// 路由级中间件
app.use('/api', (req, res, next) => {
console.log('API 请求')
next()
})
// 错误处理中间件(4个参数)
app.use((err, req, res, next) => {
console.error('错误:', err.message)
res.status(500).send('服务器错误')
})内置中间件
js
app.use(express.json()) // 解析 JSON 请求体
app.use(express.urlencoded({ extended: true })) // 解析 URL-encoded
app.use(express.static('public')) // 静态文件服务app.use(express.json()) // 解析 JSON 请求体
app.use(express.urlencoded({ extended: true })) // 解析 URL-encoded
app.use(express.static('public')) // 静态文件服务跨域处理 (CORS)
手动设置中间件
js
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
// 预检请求直接结束
if (req.method === 'OPTIONS') {
return res.sendStatus(204)
}
next()
})app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
// 预检请求直接结束
if (req.method === 'OPTIONS') {
return res.sendStatus(204)
}
next()
})使用 cors 包
bash
npm install corsnpm install corsjs
const cors = require('cors')
app.use(cors()) // 允许所有来源
// 配置选项
app.use(cors({
origin: ['http://localhost:3000'],
credentials: true,
methods: 'GET, POST, PUT, DELETE, OPTIONS'
}))const cors = require('cors')
app.use(cors()) // 允许所有来源
// 配置选项
app.use(cors({
origin: ['http://localhost:3000'],
credentials: true,
methods: 'GET, POST, PUT, DELETE, OPTIONS'
}))URLSearchParams
用于处理 URL 查询字符串:
js
const query = new URLSearchParams('foo=bar&baz=qux')
query.get('foo') // 'bar'
query.has('foo') // true
query.append('key', 'value')
query.set('foo', 'new') // 修改
query.delete('foo') // 删除
query.toString() // 'baz=qux&key=value'
// 转对象
Object.fromEntries(new URLSearchParams('foo=bar'))
// { foo: 'bar' }const query = new URLSearchParams('foo=bar&baz=qux')
query.get('foo') // 'bar'
query.has('foo') // true
query.append('key', 'value')
query.set('foo', 'new') // 修改
query.delete('foo') // 删除
query.toString() // 'baz=qux&key=value'
// 转对象
Object.fromEntries(new URLSearchParams('foo=bar'))
// { foo: 'bar' }常用工具包
js
// cors — 跨域
const cors = require('cors')
// body-parser — 请求体解析(Express 4.16+ 已内置)
// 直接使用 express.json() / express.urlencoded()
// morgan — 请求日志
const morgan = require('morgan')
app.use(morgan('dev'))
// multer — 文件上传
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file)
})
// formidable — 文件上传(另一种方式)
const formidable = require('formidable')
app.post('/upload', (req, res) => {
const form = new formidable.IncomingForm()
form.parse(req, (err, fields, files) => {
// fields: 普通字段, files: 上传文件
})
})
// express-session — Session 中间件
const session = require('express-session')
app.use(session({
secret: 'your-secret-key',
resave: true,
saveUninitialized: true
}))
// connect-mongo — Session 存储到 MongoDB
const MongoStore = require('connect-mongo')(session)
app.use(session({
secret: 'key',
store: new MongoStore({ url: 'mongodb://localhost:27017/myapp' }),
resave: true,
saveUninitialized: true
}))
// cookie-parser — Cookie 解析
const cookieParser = require('cookie-parser')
app.use(cookieParser())// cors — 跨域
const cors = require('cors')
// body-parser — 请求体解析(Express 4.16+ 已内置)
// 直接使用 express.json() / express.urlencoded()
// morgan — 请求日志
const morgan = require('morgan')
app.use(morgan('dev'))
// multer — 文件上传
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file)
})
// formidable — 文件上传(另一种方式)
const formidable = require('formidable')
app.post('/upload', (req, res) => {
const form = new formidable.IncomingForm()
form.parse(req, (err, fields, files) => {
// fields: 普通字段, files: 上传文件
})
})
// express-session — Session 中间件
const session = require('express-session')
app.use(session({
secret: 'your-secret-key',
resave: true,
saveUninitialized: true
}))
// connect-mongo — Session 存储到 MongoDB
const MongoStore = require('connect-mongo')(session)
app.use(session({
secret: 'key',
store: new MongoStore({ url: 'mongodb://localhost:27017/myapp' }),
resave: true,
saveUninitialized: true
}))
// cookie-parser — Cookie 解析
const cookieParser = require('cookie-parser')
app.use(cookieParser())模板引擎 (EJS)
配置
js
app.set('view engine', 'ejs')
app.set('views', __dirname + '/views')
// 使用 .html 后缀
app.engine('html', require('ejs').__express)app.set('view engine', 'ejs')
app.set('views', __dirname + '/views')
// 使用 .html 后缀
app.engine('html', require('ejs').__express)渲染
js
app.get('/', (req, res) => {
res.render('index', { title: '首页', message: 'Hello' })
})app.get('/', (req, res) => {
res.render('index', { title: '首页', message: 'Hello' })
})EJS 语法
ejs
<%= 变量 %> <!-- 输出转义后的内容 -->
<%- 变量 %> <!-- 输出原始 HTML -->
<% 代码 %> <!-- 执行 JavaScript -->
<%# 注释 %> <!-- EJS 注释 -->
<%- include('header') %> <!-- 引入模板 -->
<!-- 循环 -->
<% for(let i = 0; i < arr.length; i++) { %>
<li><%= arr[i] %></li>
<% } %>
<!-- 条件 -->
<% if (condition) { %>
<p>条件成立</p>
<% } %><%= 变量 %> <!-- 输出转义后的内容 -->
<%- 变量 %> <!-- 输出原始 HTML -->
<% 代码 %> <!-- 执行 JavaScript -->
<%# 注释 %> <!-- EJS 注释 -->
<%- include('header') %> <!-- 引入模板 -->
<!-- 循环 -->
<% for(let i = 0; i < arr.length; i++) { %>
<li><%= arr[i] %></li>
<% } %>
<!-- 条件 -->
<% if (condition) { %>
<p>条件成立</p>
<% } %>
Cao Note