WEB开发: Node.js路由之由浅入深(一) - 全栈工程师入门

作为一个使用Node.js多年的开发者,我已经习惯于用Node.js写一些web应用来为工作服务,因为实现快速、部署简单、自定义强。今天我们一起来学习一个全栈工程师必备技能:web路由。(观看此文的前提是默认你已经装好nonde.js了)

Node.js 中的路由是构建 Web 应用的核心概念之一,帮助我们根据用户请求的 URL 和 HTTP 方法(GET、POST 等)做出不同的响应。

下面我们由浅入深,循序渐进地讲解 Node.js 的路由实现:


1. 什么是路由?

【路由(Routing)】是指确定服务器响应用户请求的方式,也就是你访问网站的哪个路径,服务器根据路径响应你相应的内容。

比如某网站 www.duniang.com/路由1 、 www.duniang.com/路由1/路由1的儿子

路由主要根据两个要素:

  • 请求的 URL(如 /home/about
  • 请求的方法(如 GETPOSTPUTDELETE
    关于这一点网上有很多讨论,很多人基本就是 GET /  POST 一招吃遍天下,这也无可厚非。不过建议开发者还是老老实实 规规矩矩的把习惯养好,该PUT就PUT 该DELETE就DELETE。

2. 用原生 Node.js 实现简单路由

用原生的 http 模块,我们可以通过检查请求的 URL 和方法来实现路由。以下是一个简单的例子:

const http = require('http');

const server = http.createServer((req, res) => {
  const { url, method } = req;

  if (url === '/' && method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Welcome to Home Page');
  } else if (url === '/about' && method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('This is the About Page');
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Page Not Found');
  }
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

特点:

  • 手动判断 urlmethod
  • 适合学习,但不适合复杂应用,代码难以维护。

http是node内核自带的网络服务模块,可以快速创建http服务。 

将上面代码命名为 app.js ,使用  node app.js 命令 启动

创建了一个端口为3000的 webServer,我我们可以通过 http://127.0.0.1:3000访问:


3. 使用 Express 简化路由

http 这个模块使用起来还是不太方便,观感不太好,代码量也比较大,如果路由复杂,要写很多代码。所以就有了 Express

Express 是一个轻量级、流行的 Node.js 框架,它对路由的处理非常直观。我们可以用它创建清晰、可扩展的路由。

安装 Express:

npm install express

简单路由示例:

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Welcome to Home Page');
});

app.get('/about', (req, res) => {
  res.send('This is the About Page');
});

// 404 handler
app.use((req, res) => {
  res.status(404).send('Page Not Found');
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

优点:

  • 简洁的 API,如 app.get()app.post()
  • 支持中间件,可以扩展功能(如验证、日志)。

上面这个代码就清楚多了。 Express在现实中的应用非常广泛,它简单、直观,使用起来也很灵活。


4. 动态路由

动态路由允许我们为具有相似结构的 URL 创建单一路由。例如,处理用户的 ID:

app.get('/user/:id', (req, res) => {
  const userId = req.params.id; // 获取动态参数
  res.send(`User ID is ${userId}`);
});

访问 http://localhost:3000/user/123,响应为:

User ID is 123

请注意,这里的网址是 /user/minstbe  后面这个/minstbe 本来应该是一个路由,但是这里被定义为一个参数 ,它等效于 /user?id=minstbe 。很多时候我们如果不希望网页带有问号、等于号,就可以用这种方式来定义传参。

req.params:存储动态 URL 参数。

 如果我们在服务器端 console.log(req.params)  就会看到打印出了这个Object类型的参数:


5. 路由模块化

当路由逻辑增多时,我们可以将路由分离到单独的文件中,提高代码的可读性和可维护性。实际生产过程中,还会用到更加高级的分离方式 这个我们以后再介绍。

1. 创建路由模块(routes/user.js):

在webServer的主目录下创建 文件夹 routes ,并创建user.js,用来对 /user做出响应 

const express = require('express');
const router = express.Router();

router.get('/:id', (req, res) => {
  const userId = req.params.id;
  res.send(`User Profile of ID: ${userId}`);
});

module.exports = router;

2. 在主文件中引入路由模块(index.js):

const express = require('express');
const app = express();
const userRoutes = require('./routes/user'); // 这里引入了这个路由模块

app.use('/user', userRoutes); // 访问路径为 /user/:id

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

上面两个文件结合使用,启动index.js 后如下: 


6. 中间件与路由结合

中间件是在路由处理前或后执行的一段代码,用于实现日志、验证、解析等功能。

中间件在Node.js的webServer中非常重要,很多功能都是在中间件实现的,通过中间件处理获取到的内容,再交给后面的api来处理。 

示例:

const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next(); // 必须调用 next() 才能进入下一个中间件或路由
};

app.use(logger);

app.get('/', (req, res) => {
  res.send('Home Page with Logger');
});

 下面是在/user 之前 加入了一个中间件,也就是显示 访问方式 和 路径,然后再继续 交给 /user判断处理:(请注意控制台的输出)


7. 高级路由功能

  1. 处理多种 HTTP 方法:
app.route('/book')
  .get((req, res) => res.send('Get a book'))
  .post((req, res) => res.send('Add a book'))
  .put((req, res) => res.send('Update a book'));

app.route() 是 Express 提供的一个链式路由定义方法,用于处理针对 同一路径 的多个 HTTP 方法(如 GETPOSTPUT 等)的请求。

工作原理

app.route(path) 会创建一个单独的路由路径对象,可以通过链式调用分别为该路径定义不同的 HTTP 方法处理逻辑。这种写法能使代码更加清晰、结构更紧凑。


具体解析

app.route('/book')
  .get((req, res) => res.send('Get a book'))
  .post((req, res) => res.send('Add a book'))
  .put((req, res) => res.send('Update a book'));
  1. app.route('/book')
    定义了一个路径 /book 的路由。

  2. .get()

    • 处理 GET /book 请求。
    • 回调函数 (req, res) 用于返回一个响应,当前返回内容是 'Get a book'
  3. .post()

    • 处理 POST /book 请求。
    • 回调函数 (req, res) 返回 'Add a book'
  4. .put()

    • 处理 PUT /book 请求。
    • 回调函数 (req, res) 返回 'Update a book'

等价写法

上述代码的功能可以用多个单独的路由来实现:

app.get('/book', (req, res) => res.send('Get a book'));
app.post('/book', (req, res) => res.send('Add a book'));
app.put('/book', (req, res) => res.send('Update a book'));

对比:

  • 使用 app.route() 方法:
    • 逻辑集中在一个地方,便于管理和阅读。
    • 适合路径相同但处理方法不同的场景。
  • 使用分开定义的路由:
    • 路径重复,代码冗长,不够直观。

扩展:何时使用 app.route()

  1. 当一个路径需要支持多种 HTTP 方法时,比如 /book 需要处理 GETPOSTPUT
  2. 希望减少路径的重复书写,提高代码可读性和组织性。

注意:

  • app.route() 仅适用于同一个路径。如果处理的路径不同(比如 /book/author),仍需单独定义路由。
  • 它仅是 Express 提供的一种语法糖,本质上和单独写多个路由的逻辑一样。
  1. 正则匹配路由:
app.get(/.*fly$/, (req, res) => {
  res.send('Route matched with /.*fly$/');
});
// 例如,访问 /butterfly、/dragonfly 都可以匹配

好了 今天,就简单介绍一下,下次再继续!

  1. 原生实现:适合理解底层原理。
  2. Express:简化路由逻辑,是构建 Web 应用的主流选择。
  3. 动态路由:为类似的请求模式处理提供便利。
  4. 模块化路由:适合复杂项目。
  5. 中间件支持:增强功能的可扩展性。

可以从简单的例子开始尝试,然后逐渐增加复杂度,适应实际的开发场景!你想尝试哪种实现?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/930702.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

新书速览|循序渐进Node.js企业级开发实践

《循序渐进Node.js企业级开发实践》 1 本书内容 《循序渐进Node.js企业级开发实践》结合作者多年一线开发实践,系统地介绍了Node.js技术栈及其在企业级开发中的应用。全书共分5部分,第1部分基础知识(第1~3章)&#xf…

二代证信息读写器安卓身份证手持终端pda

HT530是一款可满足不同应用需求的多功能身份证核验手持机。Android 10操作系统,搭载高性能8核心2.0G主频处理器,5.5寸高清大屏,1300万摄像头;内存2G16G,4G64G可选。条码扫描(扫描头可选)、可离线采集、读取…

Redis的高可用之哨兵模式

Redis哨兵主要是解决Redis主从同步时主数据库宕机问题,使其能够自动进行故障恢复,提高Redis系统的高可用性。 1. 哨兵的作用: 监控:哨兵通过心跳机制监控主库和从库的存活性。 选主:当主库宕机时,哨兵会选举出一个领…

2024最新版python+pycharm安装与配置(mac和window都有讲)

PS:这篇是对于初学者的pythonpycharm配置教程 ,配置完成后可以直接看我的python学习笔记来进行python全套学习目前正在持续更新。 目录 python以及pycharm的安装配置一、下载安装Python1、python环境检查2、系统环境检查3、python下载4、开始安装5、检查…

【css】基础(二)

本专栏内容为:前端专栏 记录学习前端,分为若干个子专栏,html js css vue等 💓博主csdn个人主页:小小unicorn ⏩专栏分类:css专栏 🚚代码仓库:小小unicorn的代码仓库🚚 &a…

OceanBase 的探索与实践

作者:来自 vivo 互联网数据库团队- Xu Shaohui 本文总结了目前我们遇到的痛点问题并通过 OceanBase 的技术方案解决了这些痛点问题,完整的描述了 OceanBase 的实施落地,通过迁移到 OceanBase 实践案例中遇到的问题与解决方案让大家能更好的了…

【开源免费】基于Vue和SpringBoot的服装生产管理系统(附论文)

博主说明:本文项目编号 T 066 ,文末自助获取源码 \color{red}{T066,文末自助获取源码} T066,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

租赁小程序的优势与应用场景解析

内容概要 租赁小程序,听起来是不是很酷?其实,它就是一个让你可以方便地租借各种高成本但用得不频繁的商品的平台。想象一下,当你需要租一件派对用的华丽小礼服,或是想体验一下超酷的运动器材,租赁小程序就…

MySQL 权限管理分配详解

MySQL 权限管理分配详解 MySQL权限系统的工作原理权限表的存取用户通过权限认证、进行权限分配的流程账号管理我们常用的授权all privileges到底有哪些权限呢?以及带来的安全隐患有哪些?创建账户的时候最好分配指定的权限,这样子安全也高管理…

使用C#开发VTK笔记(一)-VTK开发环境搭建

一.使用C#开发VTK的背景 因为C#开发的友好性,一直都比较习惯于从C#开发程序。而长期以来,都希望有一个稳定可靠的三位工程数模的开发演示平台,经过多次对比之后,感觉VTK和OpenCasCade这两个开源项目是比较好的,但它们都是用C++编写的,我用C#形式开发,只能找到发布的C#组…

React 组件中 State 的定义、使用及正确更新方式

​🌈个人主页:前端青山 🔥系列专栏:React篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容React 组件中 State 的定义、使用及正确更新方式 前言 在 React 应用开发中,state …

长沙市的科技查新机构有哪些

中南大学图书馆科技查新站: 中南大学图书馆科技查新站成立于2003年12月,中南大学图书馆科技查新站作为教育部首批批准的科技查新工作站之一,具备了在全国范围内开展科技查新工作的专业资质。 长沙理工大学科技查新工作站: 长沙理…

数组 - 八皇后 - 困难

************* C topic: 面试题 08.12. 八皇后 - 力扣(LeetCode) ************* Good morning, gays, Fridary angin and try the hard to celebrate. Inspect the topic: This topic I can understand it in a second. And I do rethink a movie, …

IDEA的service窗口中启动类是灰色且容易消失

大家在学习Spring Cloud的过程中,随着项目的深入,会分出很多个微服务,当我们的服务数量大于等于三个的时候,IDEA会给我们的服务整理起来,类似于这样 但是当我们的微服务数量达到5个以上的时候,再启动服务的时候,服务的启动类就会变成灰色,而且还容易丢失 解决方法 我们按住…

threejs相机辅助对象cameraHelper

为指定相机创建一个辅助对象,显示这个相机的视锥。 想要在场景里面显示相机的视锥,需要创建两个相机。 举个例子,场景中有个相机A,想要显示相机A的视锥,那么需要一个相机B,把B放在A的后面,两个…

应用层协议/传输层协议(UDP)

目录 应用层 如何自定义应用层协议? 序列化方式 1.基于行文本的方式来传输 2.基于xml的方式 3.基于json的方式 4.yml的形式 5.protobuffer(pb)形式 传输层 端口号 协议 UDP 校验和 CRC TCP TCP/IP五层协议 应用层 -- 传输层 -- 网络层 -- 数据链路层…

cocotb value cocotb—基础语法对照篇

cocotb—基础语法对照篇 import cocotb from cocotb.triggers import Timer from adder_model import adder_model from cocotb.clock import Clock from cocotb.triggers import RisingEdge import randomcocotb.test() async def adder_basic_test(dut):"""Te…

【NoSQL数据库】Hbase基本操作——数据库表的增删改查

目录 一、Hbase原理 二、HBase数据库操作 三、遇到的问题和解决方法 一、Hbase原理 HBase的数据模型: 行键 时间戳 列族:contents 列族:anchor 列族:mime “com.cnn.www” T9 Achor:cnnsi.com”CNN” T8 Achor:…

【NLP高频面题 - LLM架构篇】大模型使用SwiGLU相对于ReLU有什么好处?

【NLP高频面题 - LLM架构篇】大模型使用SwiGLU相对于ReLU有什么好处? 重要性:★★★ 💯 NLP Github 项目: NLP 项目实践:fasterai/nlp-project-practice 介绍:该仓库围绕着 NLP 任务模型的设计、训练、优化…