【Express零基础入门】 | 构建简易后端服务的核心知识
0 序言
本文为Express框架的入门学习笔记,将围绕路由
、中间件
、静态文件服务
和模板引擎
等核心内容,讲解如何使用Express搭建简易后端服务。通过学习来了解Express对Node.js的封装优势
,掌握其基础用法,包括创建服务、定义路由、使用中间件、处理静态资源及错误等基础内容,这些知识对后续后端相关开发有一定帮助。
Express是Node.js中知名度高、受欢迎的开发框架,它封装了Node.js底层API,屏蔽繁琐细节,降低学习成本。本文我们的学习内容包括路由、中间件、静态文件服务和模板引擎。
本次的基础环境如下:
- 系统:Windows
- Node版本:22.18.0
- Npm版本:10.9.3
1 创建第一个demo
1.1 使用Node.js内置http模块搭建服务
1.1.1 操作步骤
1.创建文件夹并进入:
mkdir express-demo && cd express-demo
2.创建server.js
文件,添加代码:
// 引入Node.js内置的http模块,该模块提供了创建HTTP服务器和客户端的功能
const http = require('http')// 使用http模块的createServer方法创建一个HTTP服务器实例
// 回调函数接收两个参数:req(请求对象)和res(响应对象)
const server = http.createServer((req, res) => {// 设置响应状态码为200,表示请求成功res.statusCode = 200// 设置响应头Content-Type为text/html,告知客户端返回的是HTML格式内容res.setHeader('Content-Type', 'text/html')// 发送响应内容并结束响应,这里返回"hello world"res.end('hello world')
})// 让服务器监听3000端口
// 回调函数在服务器启动成功后执行,打印提示信息
server.listen(3000, () => {console.log('服务已启动...');
})
3.运行服务:
node server.js
运行后打开任意浏览器在地址栏输入 http://localhost:3000 ,按下回车键。
如果服务器正常运行(终端显示 “服务已启动…”),浏览器页面会显示 hello world 。
1.2 使用Express搭建服务
在前面1.1小节用 Node.js 内置 http 模块搭建服务中,我们实现了最基础的 HTTP 服务器,但我们会发现存在以下两个问题:
代码冗余:处理路由(区分 / /about 等接口)、设置响应头、处理请求方法(GET/POST)时,需要手动写大量条件判断。
扩展性差:后续要加中间件(日志、权限校验)、模板引擎(渲染 HTML),需要自己从头实现。
开发效率低:每次改代码都要重启服务,且没有现成工具简化流程。
这个时候我们可以使用Express来搭建服务,作为 Node.js 生态中最经典的 Web 框架,能用更简洁的语法解决上述问题。下面用 Express 重构服务,对比感受差异。
1.2.1 操作步骤
1.初始化项目并安装Express:
npm init # 一路回车生成package.json
npm install express
这个文件会被自动创建。
2.改写server.js
:
// 引入Express框架,Express是基于Node.js的Web应用开发框架,简化了HTTP服务器的创建和管理
const express = require('express')// 创建Express应用实例,app对象包含了所有用于构建Web应用的方法
const app = express()// 定义一个GET请求的路由,当客户端访问根路径"/"时,执行回调函数处理请求
// req:请求对象,包含客户端发送的请求信息(如参数、 headers等)
// res:响应对象,用于向客户端返回响应(如发送数据、设置状态码等)
app.get('/', (req, res) => {// 通过res.send()方法向客户端发送响应内容"hello world"// Express会自动根据内容类型设置响应头,并结束响应res.send('hello world')
})// 让服务器监听3000端口,启动服务
// 回调函数在服务器成功启动后执行,打印提示信息
app.listen(3000, () => {console.log('服务已启动...');
})
同样在终端上启动服务,
node server.js
运行结果一样的,
1.3 Request和Response对象
- Request对象(
req
):请求对象,包含网络请求的属性(如参数、cookie等)。 - Response对象(
res
):响应对象,可执行响应操作(如返回内容、设置状态等)。
查看所有API:https://www.expressjs.com.cn/4x/api.html#req
1.4 路由机制
- 区分接口的依据:请求方式+接口URL。
- Express中定义路由的方式:
app.METHOD(URL, CALLBACK)
,通过请求方式和URL区分请求并执行响应。
1.5 nodemon工具
在前面介绍中,我们遇到一个低效问题:
每次修改代码,比如改了 server.js 的响应内容时都要手动执行 Ctrl + C 停止服务,再重新输入 node server.js 启动。如果一天改几十次代码,光重启服务就要浪费大量时间。
nodemon 能自动检测代码变化,自动重启服务,避免手动重启,使用步骤如下:
1.安装:
npm install nodemon --save-dev
2.修改package.json
的scripts
:
{"scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "nodemon server.js"}
}
3.启动服务:
npm start
2 核心概念
在前面使用 Express 搭建服务 中,我们用 app.get(‘/’, …) 定义了 “访问根路径时返回 hello world,但实际 Web 应用不可能只有一个接口 —— 比如一个博客网站,需要有首页(/)、文章列表(/posts)、文章详情(/posts/123)、用户中心(/user)等不同地址。
路由就是用来解决不同地址返回不同内容
的核心机制:它能根据客户端请求的 URL 路径 和 HTTP 方法(GET/POST 等),精准匹配对应的处理逻辑,让服务器知道当用户访问 X 地址时,该做什么操作
。
2.1 路由
2.1.1 概念
类似访问网站的地址,用于判断客户端调用的接口。
2.1.2 路由方法
1.支持HTTP方法:get
、post
、put
、delete
等,使用方式为app.METHOD(URL, CALLBACK)
。
程序示例:
const express = require('express')
const app = express()app.get('/', (req, res) => {res.send('hello world')
})app.post('/about', (req, res) => {res.send({ name: '小明', age: 18 })
})
2.特殊方法app.all()
:匹配所有请求方法的路径,示例:
app.all('/about', function(req, res) {res.send({name: 'jackie',age: 18})
})
2.1.3 路由路径
类型:字符串、字符串模式(基于正则简化语法)、正则表达式。
说明:Express 路由路径依赖 path-to-regexp
库解析,特殊字符(?
、+
、*
等)需遵循正则语法规则。以下示例均经过版本兼容测试,可直接使用。
字符串模式示例(基于正则简化语法)
字符串模式通过特殊符号号实现模糊匹配,核心规则与正则表达式一致:
-
?
修饰符:匹配前面的字符 0 次或 1 次(实现“可选字符”效果)
示例:匹配路径/acd
(b
出现 0 次)和/abcd
(b
出现 1 次)// 注意:? 修饰的是前面紧邻的字符(此处为 b),表示 b 可选 app.get('/ab?cd', function(req, res) {// 当访问 http://localhost:3000/acd 或 http://localhost:3000/abcd 时触发res.send('匹配到路径:/ab?cd(b 可选)'); });
-
+
修饰符:匹配前面的字符 1 次或多次
示例:匹配/abcd
(b 出现 1 次)、/abbcd
(b 出现 2 次)、/abbbcd
(b 出现 3 次)等// + 修饰前面的 b,表示 b 至少出现 1 次 app.get('/ab+cd', function(req, res) {// 访问 http://localhost:3000/abcd 或 http://localhost:3000/abbcd 均会触发res.send('匹配到路径:/ab+cd(b 至少出现 1 次)'); });
-
*
通配符:匹配任意字符(包括空字符)
示例:匹配/abcd
(中间无字符)、/abxcd
(中间有 x)、/ab123cd
(中间有数字)等// * 表示 ab 和 cd 之间可以是任意字符(包括空字符) app.get('/ab*cd', function(req, res) {// 访问 http://localhost:3000/abcd 或 http://localhost:3000/abxyzcd 均会触发res.send('匹配到路径:/ab*cd(中间可填任意内容)'); });
正则表达式示例(精确匹配复杂规则)
当字符串模式无法满足需求时,可直接使用正则表达式定义路由路径:
- 匹配含特定字符的路径
示例:匹配所有 URL 中包含字母a
的路径(如/apple
、/banana
、/cat
不匹配)// 正则 /a/ 表示路径中包含字母 a(不区分位置) app.get(/a/, function(req, res) {// 访问 http://localhost:3000/apple 或 http://localhost:3000/abc 均会触发res.send('匹配到含 "a" 的路径'); });
- 匹配特定后缀的路径
示例:匹配所有以fly
结尾的路径(如/butterfly
、/dragonfly
)// 正则 /.*fly$/ 中,.* 表示任意字符,$ 表示以 fly 结尾 app.get(/.*fly$/, function(req, res) {// 访问 http://localhost:3000/butterfly 或 http://localhost:3000/dragonfly 均会触发res.send('匹配到以 "fly" 结尾的路径'); });
2.1.4 路由拆分
目的:当路由复杂(如用户相关、系统相关路径)时,便于管理。
拆分前:
// 引入Express框架
const express = require('express');
// 创建Express应用实例
const app = express();// 直接在app实例上定义用户相关路由
// 问题:当用户相关路由增多时,会导致入口文件臃肿
app.get('/user/list', function(req, res, next){res.send('/list'); // 返回用户列表数据
});app.get('/user/detail', function(req, res, next){res.send('/detail'); // 返回用户详情数据
});// 启动服务监听3000端口
app.listen(3000);
拆分后:
// 引入Express框架
const express = require('express');
// 创建Express应用实例
const app = express();// 1. 创建用户相关的路由模块(子路由)
// express.Router() 用于创建独立的路由对象,专门管理一类路由
const user = express.Router();// 2. 在子路由对象上定义具体路由
// 注意:这里的路径是相对路径(基于后续注册的父路径)
user.get('/list', function(req, res, next){res.send('/list'); // 实际访问路径为:/user/list
});user.get('/detail', function(req, res, next){res.send('/detail'); // 实际访问路径为:/user/detail
});// 3. 注册子路由到主应用
// 第一个参数 '/user' 是父路径,所有子路由的路径都会自动拼接该前缀
// 即子路由的 '/list' 会被解析为 '/user/list'
app.use('/user', user);// 启动服务监听3000端口
app.listen(3000);
2.2 中间件
2.2.1 概念
本质是函数,格式:
function someMiddleware(req, res, next) {// 自定义逻辑next(); // 触发下一个中间件
}
参数:req
(请求对象)、res
(响应对象)、next
(触发下一个中间件的函数)。
2.2.2 分类及使用
- 全局中间件:通过
app.use
注册,所有请求都会执行,示例:
app.use(someMiddleware)
- 路由中间件:在路由定义时注册,仅访问该路由时执行,示例:
app.get('/middleware', someMiddleware, (req, res) => {res.send('Hello World');
});
2.2.3 日志中间件示例
新建logger.js
:
function logger(req, res, next) {const time = new Date();console.log(`[${time.toLocaleString()}] ${req.method} ${req.url}`);next();
}module.exports = logger;
在server.js
中引入并全局注册:
const logger = require('./logger')
app.use(logger)
效果:访问路由时控制台打印日志,如:
[2023/2/27 15:54:29] GET /
[2023/2/27 15:54:47] POST /about
注意:若忘记调用next()
且不返回响应,服务器会卡在该中间件。
终端里面也会显示相对应的内容。
2.3 模板引擎
在前文的示例中,我们直接用 res.send(‘hello world’) 返回内容,但实际开发中,前端页面往往需要复杂的 HTML 结构、动态数据渲染(比如用户信息、文章列表)。
如果只用 res.send 拼接 HTML 字符串,会写出非常难维护的代码。
模板引擎就是为解决这些问题而生:它让 HTML 结构与动态数据分离,支持页面复用、动态渲染,还能通过布局模板统一管理页面结构。
2.3.1 概念
升级版HTML文档,用于渲染前端页面,Express支持jade
、ejs
、Handlebars
等。
2.3.2 Handlebars使用步骤
1.安装:
npm install hbs
2.创建模板文件:
views/index.hbs
:
<h1>express入门课程</h1>
<p>作为前端开发,Nodejs已经成了很多公司对我们这一岗位的硬性要求,而 Express 框架则是其中知名度最高、也是最受欢迎的Nodejs开发框架。。。。。</p>
<a href="/about">关于我们</a>
views/about.hbs
:
<h1>一起学前端开发</h1>
<p>好好学习,天天向上!</p>
- 配置模板引擎(在
server.js
中):
// 指定模板存放目录
app.set('views', 'views');
// 指定模板引擎为Handlebars
app.set('view engine', 'hbs');
- 使用模板:
app.get('/', (req, res) => {res.render('index'); // 渲染index.hbs
});app.get('/about', (req, res) => {res.render('about'); // 渲染about.hbs
})
2.3.3 动态参数传递
- 修改
about.hbs
:
<h1>前端小课堂</h1>
<p>好好学习,天天向上!!!</p>
<p>老师:{{ name }}</p>
<p>年龄:{{ age }}</p>
- 渲染时传参:
app.get('/about', (req, res) => {res.render('about', { name: 'tom', age: 38 });
})
2.4 静态文件服务
2.4.1 作用
用于客户端访问图片、视频等静态资源。
2.4.2 使用方法
比如说我的静态资源目录结构:
public
├── css
│ └── style.css
└── img└── logo.png
在server.js
中配置:
app.use(express.static('public'));
访问路径:
http://localhost:3000/css/style.css
http://localhost:3000/img/logo.png
在模板中引入:
<link rel="stylesheet" href="/css/style.css" />
2.5 处理404和服务器错误
2.5.1 处理404
作用:捕获未定义路由的请求。
实现:在所有路由后添加中间件:
app.use('*', (req, res) => {res.status(404).render('404', { url: req.originalUrl });
});
创建views/404.hbs
:
<h1>找不到你要的页面了!</h1>
<p>你所访问的路径 {{ url }} 不存在</p>
注意:需放在所有路由后面,仅当前面路由均匹配失败时生效。
2.5.2 处理内部错误
作用:捕获服务器内部代码错误。
实现:在所有路由后添加错误处理中间件:
app.use((err, req, res, next) => {res.status(500).render('500');
});
创建views/500.hbs
:
<h1>服务器好像开小差了</h1>
<p>过一会儿再试试看吧!See your later~</p>
注意:需放在所有路由后面,才能处理全部错误。
3 小结
本文介绍了Express框架的基础内容,包括环境准备、服务搭建、核心概念(路由、中间件、模板引擎、静态文件服务)及错误处理。这些是Express开发的核心知识点,掌握后可尝试搭建一个简易的后端服务。