涂料 网站 源码,网站代码审计,中国十大旅游网站,网站建设代码好难啊一、前言 Express 是一个简洁、灵活的 Node.js Web 应用框架。它基于 Node.js 的内置 HTTP 模块构建#xff0c;提供了一系列用于构建 Web 应用程序和 API 的功能#xff0c;使开发者能够更高效地处理 HTTP 请求和响应#xff0c;专注于业务逻辑的实现。 其特点包括简单易用…一、前言 Express 是一个简洁、灵活的 Node.js Web 应用框架。它基于 Node.js 的内置 HTTP 模块构建提供了一系列用于构建 Web 应用程序和 API 的功能使开发者能够更高效地处理 HTTP 请求和响应专注于业务逻辑的实现。 其特点包括简单易用、中间件机制丰富、路由系统灵活等。通过使用 Express可以快速搭建服务器处理不同类型的请求如网页渲染、数据接口提供等多种功能。 二、路由
1. 基本的路由格式
一个基本的 Express 路由由 HTTP 方法如app.get、app.post等、路径如/、/about等和一个或多个回调函数组成。例如
app.get(/, (req, res) {res.send(Hello World!);
});这里app.get表示处理 HTTP GET 请求/是请求路径(req, res) {... }是回调函数。req代表请求对象包含了请求的相关信息如请求头、请求参数等res代表响应对象用于发送响应给客户端如res.send方法用于发送响应内容。
2. 路径匹配 静态路径匹配如app.get(/about, (req, res) {... });只有当请求路径完全匹配/about时这个路由才会被触发。 动态路径匹配可以使用参数来创建动态路由。例如app.get(/users/:id, (req, res) { const id req.params.id; res.send(User ${id}); });:id是一个动态参数当请求路径类似/users/1、/users/2等时req.params.id可以获取到相应的参数值用于根据不同的用户 ID 等动态信息返回不同的响应。 路径参数的多种匹配方式 可选参数在路径中使用?来表示可选部分。例如app.get(ab?cd, (req, res) {... });可以匹配ab或者abcd这样的路径。 通配符匹配使用*来表示匹配任意字符序列。例如app.get(ab*cd, (req, res) {... });可以匹配ab后面跟着任意字符再接着cd的路径如abxyzcd等。 正则表达式匹配可以直接在路径中使用正则表达式。例如app.get(/abcd, (req, res) {... });匹配ab后面至少有一个字符再接着cd的路径符合正则表达式abcd的模式。
3. 路由方法HTTP方法
Express 支持多种 HTTP 方法来定义路由常见的有
GET 请求用于从服务器获取数据。例如获取网页内容、查询用户信息等场景。如app.get(/books, (req, res) { // 查询书籍信息并返回 });。POST 请求通常用于向服务器提交数据如提交表单数据、上传文件等。例如app.post(/login, (req, res) { // 处理用户登录信息提交 });。PUT 请求用于更新服务器上的数据。例如更新用户信息、修改文章内容等场景。app.put(/users/:id, (req, res) { // 根据用户ID更新用户信息 });。DELETE 请求用于删除服务器上的数据。比如删除用户记录、删除文件等。app.delete(/products/:id, (req, res) { // 根据产品ID删除产品信息 });。
三、 Express 中间件
中间件是在请求和响应周期中被调用的函数它可以访问请求对象req、响应对象res和应用程序的请求 - 响应循环中的下一个中间件next。中间件可以执行各种任务如日志记录、身份验证、数据预处理等然后可以选择将请求传递给下一个中间件或者路由处理函数。
1. 中间件的使用方式
单个中间件在路由处理函数中可以有一个或多个中间件。例如
app.get(/home, (req, res, next) {console.log(This is a middleware);next();
}, (req, res) {res.send(This is the home page);
});这里第一个函数是中间件它先打印一条日志然后调用next()将控制权传递给下一个函数这里是路由处理函数用于发送响应。如果不调用next()函数下一个中间件将不会被执行。
中间件数组也可以将多个中间件组合成一个数组来使用。例如
const func1 (req, res, next) {console.log(This is a middleware 1);next();
};
const func2 (req, res, next) {console.log(This is a middleware 2);next();
};
const func3 (req, res, next) {console.log(This is a middleware 3);next();
};
app.get(/list, [func1, func2, func3], (req, res) {res.send(This is the list page);
});当请求/list路径时会依次执行func1、func2、func3这三个中间件最后执行路由处理函数来发送响应。
2. 中间件之间的传值
中间件可以通过req或res对象在中间件之间传递值。例如
const func4 (req, res, next) {req.name John;res.age 33;next();
};
const func5 (req, res, next) {const name req.name;const age res.age;res.send(h1Hello ${name}, you are ${age} years old!/h1);
};
app.get(/hello, [func4, func5], (req, res) {
});在func4中间件中通过req.name和res.age设置了值然后在func5中间件中可以获取这些值来生成响应。
3. 不同类型的中间件
3.1 应用级中间件
通过app.use()方法来添加应用级中间件它可以应用于整个应用程序或者特定的路径。如果没有指定路径中间件会应用于所有的请求路径。例如
const express require(express);
const app express();
app.use((req, res, next) {console.log(This middleware is called for every request);next();
});
app.get(/hello, (req, res) {res.send(Hello World);
});
app.listen(3000, () {console.log(Server is running on port 3000);
});在这个例子中定义的中间件会在每个请求到达服务器时被调用它先打印一条日志然后通过next()函数将请求传递给下一个中间件或者路由处理函数。
3.2 特定路径的应用级中间件
可以指定中间件应用的路径这样中间件只会对匹配该路径及其子路径的请求起作用。例如
app.use(/admin, (req, res, next) {console.log(This middleware is for /admin and its sub - paths);// 可以在这里进行权限验证等操作next();
});
app.get(/admin/dashboard, (req, res) {res.send(Admin Dashboard);
});当请求/admin路径或者以/admin开头的子路径如/admin/dashboard时中间件会被调用。这对于对特定模块或功能进行统一的预处理如权限验证非常有用。
3.3 路由中间件
路由中间件和应用级中间件类似也是通过app.use()在特定路由路径下注册在路由处理函数之前执行用于对该路由的请求进行预处理等操作。例如
app.use(/api/users, (req, res, next) {console.log(This is a route - level middleware for /api/users);// 可以在这里进行用户相关的预处理如验证用户是否存在等next();
});
app.get(/api/users, (req, res) {res.send(List of users);
});这里的路由中间件会在处理/api/users路由的请求之前被调用用于对用户相关的请求进行预处理。
3.4 错误处理中间件
错误处理中间件用于捕获和处理在路由处理函数或其他中间件中抛出的错误。它的函数签名与普通中间件略有不同有四个参数(err, req, res, next)其中err参数用于接收错误对象。错误处理中间件应该放在所有其他中间件和路由定义之后这样才能捕获它们抛出的错误。例如
app.use((err, req, res, next) {console.error(err.stack);res.status(500).send(Something went wrong!);
});
app.get(/error - route, (req, res, next) {const error new Error(This is a test error);next(error);
});在这个例子中当请求/error - route时会在路由处理函数中创建一个错误对象并通过next(error)将错误传递给错误处理中间件。错误处理中间件会在控制台打印错误栈信息然后向客户端返回一个状态码为500服务器内部错误的响应消息为Something went wrong!。
3.5 内置中间件
**express.json()**用于解析application/json格式的请求体。在处理 POST 或 PUT 请求且请求体数据为 JSON 格式时非常有用。例如
app.use(express.json());
app.post(/data, (req, res) {const data req.body;// 处理接收到的JSON数据res.send(Data received);
});当客户端发送一个application/json格式的 POST 请求到/data路径时express.json()中间件会自动将请求体中的 JSON 数据解析为 JavaScript 对象并挂载到req.body上方便在路由处理函数中使用。
**express.urlencoded({ extended: false })**用于解析application/x -www-form-urlencoded格式的请求体。通常用于处理 HTML 表单提交的数据。例如
app.use(express.urlencoded({ extended: false }));
app.post(/form-data, (req, res) {const formData req.body;// 处理接收到的表单数据res.send(Form data received);
});usernamejunpassword123456这种格式的数据解析
3.6 第三方中间件
**morgan**用于日志记录它可以记录每个请求的详细信息如请求方法、请求路径、响应状态码等。例如
const morgan require(morgan);
app.use(morgan(combined));这里morgan(combined)是一种日志格式选项它会记录详细的请求信息。morgan还有其他日志格式如dev适合开发环境、common等开发者可以根据实际需求选择。
**cors**用于解决跨域资源共享问题。例如
const cors require(cors);
app.use(cors({origin: http://example.com,methods: [GET, POST],
}));这个配置允许来自http://example.com的请求使用GET和POST方法进行跨域访问。可以根据具体的业务场景调整origin允许的源、methods允许的请求方法等参数来满足跨域需求。
四、 模块化的路由中间件
express.Router是 Express 框架中的一个重要组件它提供了一种模块化的方式来定义路由。使用Router可以将路由分组并封装到独立的模块中这有助于组织大型应用程序的路由结构使代码更加清晰、易于维护和扩展。
1. 创建和使用express.Router实例
创建实例首先需要创建一个Router实例。例如
const express require(express);
const router express.Router();定义路由在Router实例上可以像在主app对象上一样定义各种 HTTP 方法的路由。例如
router.get(/, (req, res) {res.send(This is the root of the sub - router);
});
router.post(/data, (req, res) {const data req.body;res.send(Received data: ${data});
});挂载到主应用创建并定义好Router的路由后需要将其挂载到主 Express 应用上。例如
const app express();
app.use(/api, router);这里将router挂载到/api路径下这意味着router中定义的所有路由实际上是相对于/api路径的。例如router中的/路由实际上对应的是/api/路径/data路由对应的是/api/data路径。
2. 路由模块化的优势
代码结构清晰通过将相关的路由分组到不同的Router模块中可以将一个大型应用的路由按照功能模块如用户管理、产品管理、订单管理等进行划分。例如在一个电商应用中可以有一个userRouter用于处理用户相关的路由注册、登录、获取用户信息等一个productRouter用于处理产品相关的路由产品列表、产品详情、添加产品等这样的代码结构更易于理解和维护。复用性增强Router模块可以在不同的应用或者应用的不同部分复用。比如一个通用的authRouter用于处理身份验证相关的路由登录、验证 token 等可以在多个不同的微服务或者应用模块中使用只要它们遵循相同的接口和认证机制。团队协作便利在团队开发中不同的开发人员可以负责不同的Router模块这样可以并行开发减少代码冲突。例如前端开发人员和后端开发人员可以分别开发与用户界面交互相关的路由和与数据库操作相关的路由通过定义好的接口如 API 路由进行协作。
3. 中间件在express.Router中的使用
在Router级别使用中间件可以在Router实例上使用中间件这些中间件会应用到该Router所定义的所有路由上。例如
const loggerMiddleware (req, res, next) {console.log(Received a request for ${req.url});next();
};
router.use(loggerMiddleware);这里定义了一个日志记录中间件loggerMiddleware并通过router.use()将其应用到router上。这样router中所有的路由在被访问时都会先执行这个日志记录中间件。
在特定路由中使用中间件也可以在Router的特定路由中使用中间件。例如
const authMiddleware (req, res, next) {const token req.headers.authorization;if (!token) {return res.status(401).send(Unauthorized: No token provided);}// 验证token的其他逻辑next();
};
router.get(/protected - route, authMiddleware, (req, res) {res.send(This is a protected route);
});在这个例子中authMiddleware中间件只应用于/protected - route这个特定的路由。当访问该路由时会先执行中间件进行身份验证只有验证通过后才会执行路由处理函数。
4. 嵌套express.Router实例
express.Router实例可以进行嵌套以创建更复杂的路由层次结构。这在构建具有多层级关系的 API 或者应用程序时非常有用。例如在一个具有用户组和用户的应用中可以先有一个groupRouter用于处理用户组相关的路由在groupRouter内部再嵌套一个userRouter用于处理每个用户组内用户相关的路由。
const groupRouter express.Router();
const userRouter express.Router();
// 定义用户组相关的路由
groupRouter.get(/, (req, res) {res.send(List of groups);
});
groupRouter.post(/, (req, res) {res.send(Create a new group);
});
// 在用户组路由中嵌套用户路由
userRouter.get(/, (req, res) {res.send(List of users in the group);
});
userRouter.post(/, (req, res) {res.send(Add a new user to the group);
});
groupRouter.use(/:groupId/users, userRouter);
const app express();
app.use(/groups, groupRouter);在这个例子中userRouter被嵌套在groupRouter内部。groupRouter处理用户组的基本路由如获取用户组列表和创建新用户组。userRouter处理用户组内用户的相关路由如获取用户组内用户列表和添加新用户到用户组。通过groupRouter.use(/:groupId/users, userRouter)将userRouter挂载到groupRouter的/:groupId/users路径下这样就创建了一个嵌套的路由结构。当请求/groups/1/users假设1是用户组 ID时会先由groupRouter处理/groups/1部分的路由然后将请求传递给userRouter处理/users部分的路由。