当前位置: 首页 > news >正文

【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.jsonscripts

{"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方法getpostputdelete等,使用方式为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 库解析,特殊字符(?+* 等)需遵循正则语法规则。以下示例均经过版本兼容测试,可直接使用。

字符串模式示例(基于正则简化语法)

字符串模式通过特殊符号号实现模糊匹配,核心规则与正则表达式一致:

  1. ? 修饰符:匹配前面的字符 0 次或 1 次(实现“可选字符”效果)
    示例:匹配路径 /acdb 出现 0 次)和 /abcdb 出现 1 次)

    // 注意:? 修饰的是前面紧邻的字符(此处为 b),表示 b 可选
    app.get('/ab?cd', function(req, res) {// 当访问 http://localhost:3000/acd 或 http://localhost:3000/abcd 时触发res.send('匹配到路径:/ab?cd(b 可选)');
    });
    
  2. + 修饰符:匹配前面的字符 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 次)');
    });
    
  3. * 通配符:匹配任意字符(包括空字符)
    示例:匹配 /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(中间可填任意内容)');
    });
    
正则表达式示例(精确匹配复杂规则)

当字符串模式无法满足需求时,可直接使用正则表达式定义路由路径:

  1. 匹配含特定字符的路径
    示例:匹配所有 URL 中包含字母 a 的路径(如 /apple/banana/cat 不匹配)
    // 正则 /a/ 表示路径中包含字母 a(不区分位置)
    app.get(/a/, function(req, res) {// 访问 http://localhost:3000/apple 或 http://localhost:3000/abc 均会触发res.send('匹配到含 "a" 的路径');
    });
    

在这里插入图片描述

  1. 匹配特定后缀的路径
    示例:匹配所有以 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支持jadeejsHandlebars等。

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开发的核心知识点,掌握后可尝试搭建一个简易的后端服务。

http://www.lryc.cn/news/626540.html

相关文章:

  • 【Java后端】Spring Boot 全局异常处理最佳实践
  • ssl代理
  • SED项目复现学习实录
  • Milvus 可观测性最佳实践
  • Linux高效备份:rsync + inotify实时同步
  • Clonezilla live 再生龙还原系统各个版本的不同
  • Jupyter Notebook 的终极进化:VS Code vs PyCharm,数据科学的IDE王者之争
  • 27.语言模型
  • Visual Studio 2010 简体中文旗舰版 安装全过程详解(附安装包下载)
  • 草稿链(CoD):提示词技术的新王者
  • 个人使用AI开发的《PlSqlRewrite4GaussDB(PLSQL自动转换工具)1.0.1 BETA》发布
  • 【考研408数据结构-09】 图论进阶:最短路径与最小生成树
  • 【Obsidian插件】HiNote
  • iOS开发之UICollectionView为什么需要配合UICollectionViewFlowLayout使用
  • 数据结构-有序二叉树
  • 【机器学习深度学习】Ollama、vLLM、LMDeploy对比:选择适合你的 LLM 推理框架
  • HTML应用指南:利用POST请求获取全国刘文祥麻辣烫门店位置信息
  • 学习threejs,打造宇宙星云背景
  • 数据结构 二叉树 二叉树链式结构的实现
  • 大规模IP轮换对网站的影响(服务器压力、风控)
  • 测试环境搭建和部署(在Linux环境下搭建jdk+Tomcat+mysql环境和项目包的部署)
  • 【39】OpenCV C++实战篇——直线拟合、直线测距、平行线段测距;(边缘检测,剔除噪点,轮廓检测,渐进概率霍夫直线)
  • 本地文件上传到gitee仓库的详细步骤
  • Wireshark捕获电脑与路由器通信数据,绘制波形观察
  • C语言第十章内存函数
  • python numpy.random的基础教程(附opencv 图片转数组、数组转图片)
  • Dog Tricks
  • vue3项目,main.ts中设置router,在各个页面上还用引用vue-router吗
  • 性能测试报告深度解析:从冰冷数据到火热洞察
  • Flink学习