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

Express开发快速学习

创建Express项目

1. 初始化项目

首先,创建一个新目录并初始化项目:

mkdir express-app
cd express-app
pnpm init

按照提示填写项目信息,或者直接使用默认值。

2. 安装 Express

使用 pnpm 安装 Express:

pnpm add express

3. 安装完之后使用vscode打开express-app项目

第一个Express项目
// 第一个express
const express = require('express'); // 这样导入之后不容易出错// 1. 创建应用对象
const app = express();
// 2. 创建路由规则
app.get('/', (req, res) => {res.send('Hello World!');
});// 3. 监听端口,启动服务:node
app.listen(3000, function () {console.log('Example app listening on port 3000!');
});

启动项目:node src\app.js 或者

通过配置package.json文件来直接启动

 "scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "node src/app.js"},
express项目的大致目录
my-express-app/
├── node_modules/          # 项目依赖
├── public/                # 静态文件
│   ├── images/            # 图片资源
│   ├── css/               # CSS 样式表
│   └── js/                # 客户端 JavaScript
├── src/                   # 主要源代码
│   ├── Handlers/       # 控制器
│   ├── models/            # 数据模型
│   ├── routes/            # 路由
│   ├── services/          # 业务逻辑
│   ├── middlewares/       # 自定义中间件
│   ├── views/             # 视图模板 (如果使用模板引擎)
│   ├── utils/             # 工具函数
│   ├── config/            # 配置文件
│   └── app.js             # Express 应用配置
├── tests/                 # 测试文件
├── .env                   # 环境变量
├── .gitignore             # Git 忽略文件配置
├── package.json           # 项目配置和依赖
└── README.md              # 项目说明文档

安装和使用nodemon

为什么要使用 nodemon(支持热更新)

在编写调试 Node.js 项目的时候,如果修改了项目的代码,则需要频繁的手动 close 掉,然后重新启动,非常繁琐。
现在,我们可以使用 nodemon(https://www.npmjs.com/package/nodemon)这个工具,它能够监听项目文件的变化,当代码被修改后,nodemon 会自动帮助我们重新项目,极大方便了开发和调试。

  1. 本地项目安装:npm install --save-dev nodemon

  2. 之后再package.json的script里配置

{"scripts": {"dev": "nodemon app.js"}
}

路由

路由的作用:

根据前端发送的请求的路径来确定那个回调函数执行

怎么使用

确定好三个东西:请求方法,请求路径,回调函数

处理多种RestFulApi

const express = require('express');
const app = express();
app.use(express.json()); // 用于解析 JSON 请求体
app.use(express.urlencoded({ extended: true })); // 解析 application/x-www-form-urlencoded// 用户资源示例:GET /users/1?role=admin&active=true
app.get('/users/:id', (req, res) => {const userId = req.params.id; // "123"const role = req.query.role; // "admin"const active = req.query.active; // trueconst authToken = req.headers['authorization']; // 获取请求头里的参数
});app.post('/users', (req, res) => {// 创建新用户const userData = req.body; // { name: "John", email: "john@example.com" }
});app.get('/users/:id', (req, res) => {// 获取特定用户
});app.put('/users/:id', (req, res) => {// 更新整个用户资源
});app.patch('/users/:id', (req, res) => {// 部分更新用户资源
});app.delete('/users/:id', (req, res) => {// 删除用户
});
发送响应相关

响应设置

app.get("/res", (req, res) => { res.send("<h1>给前端的响应内容</h1>").set({// 设置响应体"Content-Type": "text/plain; charset=utf-8","Author": "springboot" })
})

具体发送响应介绍

   // 发送 JSON 响应(200)res.json({id: req.params.id,name: "John Doe",email: "john@example.com"});  // 创建成功,返回 201 Createdres.status(201).json({ message: "User created", id: 123 });app.get('/users/:id', (req, res) => {const user = getUserById(req.params.id);if (!user) {return res.status(404).json({ error: "User not found" });}res.json(user);
});// 匹配所有请求方法
app.all('/user', (req, res) => {res.send('User Page');
});

客户端重定向

app.get('/blbl', (req, res) => {res.redirect(301, 'https://www.bilibili.com/') // 301重定向到blbl
})

其它类型的响应

// 响应 文件(下载)
app.get('/dowmload', (req, res) => { res.download(__dirname + '/app.js')
})// 响应文件内容
app.get('/html', (req, res) => { res.sendFile(__dirname + '/app.js')
})// 响应404,直接使用use
app.use((req, res) => {res.status(404).send('404 Not Found');
});

中间件

概念

中间件本质就是一个回调函数,

中间件于路由接收器在文件里位置的先后注意:
  1. 处理404的使用app.use方法,放在

    app.listen(3000, () => {console.log('Example app listening on port 3000!');
    });
    

    之前

  2. 中间件(相当于是拦截器作用的)放在路由接收器的最前面,越靠近前面的中间件越先接收到请求

  3. 一定要在路由之前注册中间件

  4. 客户端发送过来的请求,可以连续调用多个中间件进行处理

  5. 执行完中间件的业务代码之后,不要忘记调用 next() 函数

  6. 为了防止代码逻辑混乱,调用 next() 函数后不要再额外的代码

  7. 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象

全局中间件

// 全局中间件:记录日志
function recordMiddleware(req, res, next) {// 获取 url 和 iplet { url, ip } = req;// 将信息保存到文件中 access.logconsole.log(url, ip);fs.appendFileSync(path.resolve(__dirname, '/access.log'), `${url} ${ip}\r\n`);// 调用 next,执行后续的代码,这样所有的请求都会经过这个中间件next();console.log("返回中间件!!!") // 最后响应的时候还会返回中间件
}app.use(recordMiddleware);

特定路由中间件

app.use('/user', (req, res, next) => { // 路径开头为user的请求都经过这个中间件console.log('Request Type:', req.method);next();
});app.use('/user/po', (req, res, next) => { // 访问/user/po的请求都经过这个中间件console.log('Another Middleware');res.send('Hello World!');
});

局部路由的中间件

// 定义一个局部中间件
function validateRequest(req, res, next) {if (!req.query.name) {return res.status(400).send('Name parameter is required');}next();console.log("返回中间件!!!") // 最后响应的时候还会返回中间件
}// 将局部中间件绑定到特定路由
app.get('/user', validateRequest, (req, res) => {res.send(`Hello, ${req.query.name}!`);
});

定义多个局部生效的中间件

app.get('/', mw1, mw2, (req, res) => { res.send('Home page.') })app.get('/', [mw1, mw2], (req, res) => { res.send('Home page.') })

静态资源中间件

Express 的静态资源中间件 express.static 是用于托管静态文件(如 HTML、CSS、JavaScript、图片等)的内置中间件。

前端项目打包之后交付给后端,后端就将其放在public目录之下

const express = require('express');
const app = express();// 托管public目录下的静态文件
app.use(express.static('public')); // 默认为和src同级目录下的

这样设置后,public 目录下的文件就可以通过 URL 直接访问了。例如:

  • public/css/style.css/css/style.css
  • public/images/logo.png/images/logo.png

如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下方式:

app.use('/public', express.static('public'))// 添加声明访问路径前缀

现在,可以通过带有 /public 前缀地址来访问 public 目录中的文件了:

  • http://localhost:3000/public/images/kitten.jpg
  • http://localhost:3000/public/css/style.css
  • http://localhost:3000/public/js/app.js

处理错误的中间件(返回500状态码)

为了生效,要放在最后面。

app.use((err, req, res, next) => {console.error(err.stack);res.status(500).send('Something broke!');
});

获取请求体和请求参数

1. 获取请求参数

查询参数是URL中?后面的部分,Express会自动解析这些参数,你可以通过req.query对象访问它们。

const express = require('express');
const app = express();app.get('/search', (req, res) => {// 访问查询参数const { q, page } = req.query; // 直接解析res.send(`搜索关键词: ${q}, 当前页: ${page || 1}`);
});app.listen(3000);

2. 获取请求体里的参数

先安装依赖:npm install body-parser

const express = require('express');
const bodyParser = require('body-parser');
const app = express();// 解析 application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));// 解析 application/json
app.use(bodyParser.json());app.post('/login', (req, res) => {const { username, password } = req.body; // 解析请求体里的参数res.send(`用户名: ${username}, 密码: ${password}`);
});app.listen(3000);

express怎么写接口

1. 项目文件结构
my-express-app/
├── app.js            # 主应用文件
├── routes/           # 路由文件夹
│   ├── users.js      # 用户相关路由
│   └── products.js   # 产品相关路由
├── Handlers/      # 路由处理
│   ├── userHandler.js
│   └── productHandler.js
├── models/           # 数据模型文件夹
│   ├── userModel.js
│   └── productModel.js
├── config/
│   └── db.js          # 数据库配置文件
└── package.json
└── .env               # 环境变量文件
2. 主应用文件 (app.js)
const express = require('express');
const app = express();
const PORT = 3000;// 内置中间件(全局)
app.use(express.json()); // 解析JSON请求体
app.use(express.urlencoded({ extended: true })); // 解析URL编码的请求体// 导入路由
const userRoutes = require('./routes/users');
const productRoutes = require('./routes/products');// 使用路由
app.use('/users', userRoutes); // user的进入这个路由
app.use('/products', productRoutes); // products的进入这个路由// 404处理
app.use((req, res) => {res.status(404).json({ error: 'Not Found' });
});// 错误处理
app.use((err, req, res, next) => {console.error(err.stack);res.status(500).json({ error: 'Something went wrong!' });
});// 启动服务器
app.listen(PORT, () => {console.log(`Server running on http://localhost:${PORT}`);
});
3. 路由文件 (routes/users.js)
const express = require('express');
const router = express.Router();
const userHandler = require('../Handlers/userHandler'); // 导入路由处理函数// 获取所有用户
router.get('/', userHandler.getAllUsers);// 获取单个用户
router.get('/:id', userHandler.getUserById);// 创建用户
router.post('/', userHandler.createUser);// 更新用户
router.put('/:id', userHandler.updateUser);// 删除用户
router.delete('/:id', userHandler.deleteUser);module.exports = router;
4. 路由处理函数(Handlers/userHandler)
const User = require('../models/User'); // 假设有一个 User 模型// 获取所有用户
const getAllUsers = async (req, res) => {try {const users = await User.find(); // 查询所有用户res.status(200).json(users); // 返回 JSON 数据} catch (error) {res.status(500).json({ message: "获取用户列表失败", error: error.message });}
};...// 其它路由处理函数// 导出所有处理函数
module.exports = {getAllUsers,getUserById,createUser,updateUser,deleteUser,
};
5. 配置数据库连接

安装数据库依赖:npm install mysql2

dotenv依赖: npm i dotenv

dotenv 是一个 Node.js 的零依赖模块,它的主要作用是从 .env 文件加载环境变量到 Node.js 的 process.env 中。

.env - 环境变量文件
DB_HOST=localhost
DB_USER=your_username
DB_PASSWORD=your_password
DB_NAME=your_database
PORT=3000... # 其它数据库等
创建config/db.js,定义数据库连接对象。
const mysql = require('mysql2/promise');
require('dotenv').config(); // 通常在应用启动的最开始调用const pool = mysql.createPool({host: process.env.DB_HOST,user: process.env.DB_USER,password: process.env.DB_PASSWORD,database: process.env.DB_NAME,waitForConnections: true,connectionLimit: 10,queueLimit: 0
});module.exports = pool;
之后数据模型配置:models/userModel.js - 用户模型示例
const pool = require('../config/db');const User = {// 获取所有用户getAll: async () => {const [rows] = await pool.query('SELECT * FROM users');return rows;},// 通过ID获取用户getById: async (id) => {const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);return rows[0];},// ......
};module.exports = User;
6. 封装Restfulapi响应的数据结构
function responseHandler(req, res, next) {// 成功响应方法res.success = function (data = null, message = '操作成功', code = 200) {res.json({code,message,data});};// 失败响应方法res.error = function (err = '操作失败', code = 400, data = null) {res.status(code).json({code,message:err instanceof Error ? err.message : err,data});};// data: 当前页的数据列表(list)
// total: 符合条件的总条数(totalCount)
// page: 当前页码(pageNumber)
// pageSize: 每页条数(pageSize)
// message: 业务提示信息,默认是“查询成功”
// totalPages:总页数    res.paginate = function (data, total, page, pageSize, message = '查询成功') {res.json({code: 200,message,data: {list: data,total,page,pageSize,totalPages: Math.ceil(total / pageSize)}});};next();
}

CORS跨域解决方案

1. CORS介绍

CORS(Cross-Origin Resource Sharing,跨域资源共享)由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器是否阻止前端 JS 代码跨域获取资源。

浏览器的同源安全策略默认会阻止跨域获取资源。但如果接口服务端配置了 CORS 相关的 HTTP 响应头,就可以解除浏览器端的跨域访问限制。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 使用 cors 中间件解决跨域问题

cors 是 Express 的一个第三方中间件。通过安装和配置 cors 中间件,可以很方便地解决跨域问题。使用步骤分为如下 3 步:

① 运行 npm install cors 安装中间件
② 使用 const cors = require(‘cors’) 导入中间件(允许所有来源
③ 在路由之前调用 app.use(cors()) 配置中间件

3. 预检请求

预检请求:只要符合以下任意一个条件的请求,都需要进行预检请求:

  1. 请求方式为 GET、POST、HEAD 之外的请求 Method 类型
  2. 请求头中包含自定义头字段
  3. 向服务器发送了 application/json 格式的数据

在浏览器与服务器正式通信之前,浏览器会先发送 OPTIONS 请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTIONS 请求称为“预检请求”。 服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。(发生响应请求)

Cookic和JWT

浏览器的 Cookie 在符合条件的情况下(同域名)会自动附加到 HTTP 请求头中,不需要前端手动编写代码去操作

请求头中的表现

当条件满足时,浏览器会自动在请求头中添加 Cookie 字段,例如:

GET /api/data HTTP/1.1
Host: example.com
Cookie: sessionId=abc123; username=foo
Cookie 不具有安全性

由于 Cookie 是存储在浏览器中的,而且 浏览器提供了读取 Cookie 的 API,因此 Cookie 很容易被伪造,不具有关性。因此不建议服务器将重要的隐私数据,通过 Cookie 的形式发送给浏览器。

http://www.dtcms.com/a/334145.html

相关文章:

  • 探秘gRPC——gRPC原理详解
  • B3924 [GESP202312 二级] 小杨的H字矩阵
  • Flink Stream API 源码走读 - window 和 sum
  • Kubernetes Service
  • Google C++ 风格指南
  • 大模型教机器人叠衣服:2025年”语言理解+多模态融合“的智能新篇
  • Cmake学习笔记
  • 小白学习《PCI Express体系结构导读》——第Ⅰ篇第1章PCI总线的基本知识
  • 如何使用 Git 修改已推送 Commit 的用户名和邮箱
  • FFmpeg QoS 处理
  • 正点原子【第四期】Linux之驱动开发篇学习笔记-1.1 Linux驱动开发与裸机开发的区别
  • C语言(11)—— 数组(超绝详细总结)
  • [论文阅读] 人工智能 | 对话中的属性与情感:LLM如何通过多代理反思实现细粒度理解
  • 利用爬虫按图搜索淘宝商品(拍立淘)实战指南
  • 教材采购管理系统(java)
  • OpenEuler 等 Linux 系统中运行 Vue 项目的方法
  • 【P14 3-6 】OpenCV Python——视频加载、摄像头调用、视频基本信息获取(宽、高、帧率、总帧数)
  • C++ string类操作全解析(含模拟实现)
  • 高等数学 8.4 空间直线及其方程
  • [Linux] Linux硬盘分区管理
  • AI 搜索时代:引领变革,重塑您的 SEO 战略
  • MySQL异步连接池的学习(五)
  • PHP反序列化的CTF题目环境和做题复现第2集_POP链构造
  • 生产环境Redis缓存穿透与雪崩防护性能优化实战指南
  • 马拉松|基于SSM的马拉松报名系统微信小程序的系统设计与实现(源码+数据库+文档)
  • 【数据分享】大清河(大庆河)流域上游土地利用
  • Java设计模式详细解读
  • 双向SSL认证之Apache实战配置
  • 【分数求和1】
  • LintCode第116题-跳跃游戏