首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >NodeJS背后的人:Express

NodeJS背后的人:Express

作者头像
Java_慈祥
发布于 2024-08-06 06:52:51
发布于 2024-08-06 06:52:51
56900
代码可运行
举报
运行总次数:0
代码可运行

NodeJS背后的人:Express

前置知识:需要掌握了解: JavaScript基础语法Node.JS环境API前端工程\模块化 ·····

早就听说NodeJS的强大,前端领域几乎无人不知、无人不晓,甚至在后端领域也有它的英姿👤

目前江湖中,web后端领域无疑是Java的天下,但: 作为一个Java开发不得不承认,它的内卷还有Spring的沉重…

对于一个小型项目来说,Java的各种框架|代码|包|开发时长|学习成本,稍微有亿点点大,那么,有没有一种更敏捷快速的开发呢》

这时:Node携手Express 出现了:首先Node本身就是JS运行环境,支持部署在服务器端,HTTP模块进行接口开发,集合Express即可更高效完成开发⛏️

Express

Express 是基于 Node.js 平台的极简、灵活的web 应用开发框架 -🔗🔗

简单来说:Express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用:HTTP 服务)

Express使用🚀:

Express 本身是一个 npm 包,所以可以通过 npm 安装:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm init -y
npm i express

Code目录下:edemo01.js 第一个Express Demo案例,和Node HTTP模块创建服务方式类似:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** Express简单服务应用:*/
//1.导入express模块
const express = require('express');

//2.创建应用对象
const app = express();
//3.定义服务路由: 
app.get('/demo', (req,res)=>{ res.end('Hello ExpressServer'); })
//4.监听端口、启动服务: 
app.listen(5400, ()=>{ console.log('服务已经启动, 端口监听为 5400...'); });

ndoe edemo01.js 启动服务,最后—>浏览器请求: http://127.0.0.1:5400/demo 页面响应 Hello ExpressServer 测试成功!

Express路由🌐:

路由是网络通信中的一个核心概念:确保数据包能够以最有效的方式从源到达目的地;

Express路由: 确定了应用程序如何响应客户端对特定端点的请求,每个路由可以有一个或多个回调处理函数,当路由匹配时执行;

路由的组成: 端点是:URI/路径+特定的HTTP请求方法(GET\POST... 采用以下结构:app.METHOD(PATH, HANDLER)

  • appexpress 的一个实例:应用对象,由express()构造函数创建;
  • METHOD 指定HTTP的请求方法,常见的请求方式:GETPOSTPUTDELETE ···
  • (PATH,Handler)PATH定义匹配的路由路径,Handler 路由匹配时执行的回调函数:(请求对象req,响应对象res)=>{}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//多种路由规则: 
//浏览器默认GET请求,其他请求可以使用接口工具进行测试;
app.get('/getD', (req,res)=>{ res.end('常用于获取数据'); })
app.put('/putD', (req,res)=>{ res.end('常用于更新数据'); })
app.post('/postD', (req,res)=>{ res.end('常用于提交数据'); })
app.delete('/deleteD', (req,res)=>{ res.end('常用于删除资源'); })

Express 特殊路由: app.get('/‘,(req,res)=>{}) 几乎所有的网站都必备该请求方式,get/通常表示:请求的根路径应用的入口;常用于网站主页

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//处理根路径的 GET 请求
app.get('/', (req, res) => { res.send('<H1>欢迎访问我的网站!</H1>'); });
  • 浏览器: 127.0.0.1:5400 即可直接请求响应!根路径的路由:允许你定义应用的默认页面或入口点

Express all全路由: app.all('xxx',(req,res)=>{}) 支持处理所有 HTTP 请求方法的路由处理器,只要请求路径匹配,即:路由所有的请求方式;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//all全路由请求:
//处理所有请求方法的路由
app.all('/allD', (req, res) => { res.end("无论是 GET、POST、PUT 还是其他任何请求方法,都会由这个路由处理器处理"); });

//自定义 404 路由: *表示接受所有请求路径,通常定义在最后用于: 兜底404
app.all('*', (req, res) => { res.end("<H1>404</H1>"); });
  • 路由的定义匹配规则: 建议:all全路由定义在最后位置 因为:Express 在处理请求时会按照路由定义的顺序进行匹配,找到第一个匹配的路由就停止;
  • 为避免干扰,相同请求路径|路由的操作被干扰,通常all定义在最后用于兜底操作;

获取请求报文参数:

原生Node 可以通过HTTP模块获取请求报文: 但对于一些参数获取存在一些不便:获取请求路径|参数|请求头...

Express对其进行了封装更方便获取请求报文中的数据:并兼容原生的HTTP模块获取方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//定义服务路由: 
//假设请求 URL: http://127.0.0.1:5400/request?name=wsm&a=123
app.get('/request', (req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8');    //解决中文乱码;
    //NodeJS原生获取请求报文:Express兼容原生
    console.log("获取请求URL: "+req.url);                   	 ///request?name=wsm
    console.log("获取请求方式: "+req.method);               		//GET
    console.log("获取请求版本号: "+req.httpVersion);        	   //1.1

    console.log("获取请求头对象: "+req.headers);                  //[obj,obj]
    console.log("获取请求头对象[接受语言]: "+req.headers['accept-language']);   

    //Express API获取请求报文:
    console.log("获取发请求设备IP: "+req.ip);                       //::ffff:127.0.0.1
    console.log("获取URL路径字符串: "+req.path);                    ///request
    console.log("获取URL查询字符串: "+JSON.stringify(req.query));   //{"name":"wsm","a":"123"}         
    console.log("获取请求头对象参数值: "+req.get("accept-language"));
    
    res.end('response succeed!!!'); }
);
URL路由命名参数:

Express 路由中的命名参数: 是一种在 路由URL路径 中定义参数名称来捕获请求中特定部分的方法,

这允许你在路由处理器中访问这些参数的值,从而根据请求的不同条件执行不同的逻辑

语法: 在路由URL中:命名参数 进行定义, 回调函数通过req.param 获取命名参数值


举例: 某个商城的商品页面,可能根据不同的商品id,而展示不同的URL

  • https://127.0.0.1:5400/details/7654321.html
  • https://127.0.0.1:5400/details/1234567.html 虽然此处都是不同的路由,但仅需一个路由规则即可匹配,同时响应不同的页面;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//路由命名参数
//:命名参数定义命名参数,并获取值;
app.get("/details/:commodityID",(req,res)=>{
    //回调函数通过:req.params 获取命名参数的值;
    const {commodityID} = req.params;   //结构赋值获取结果;
    //if(判断商品ID.html是否存在返回页面)
    //else if(..其他操作..)
    //else{..404..} 
    res.end(`商品ID ${commodityID}`);
});

上述路由定义: 所有的 https://127.0.0.1:5400/details/???? 都会进入该路由回调处理… 一定程度减少了代码开发,提高路由规则|灵活

路由命名参数注意事项:⚡⚡

  • 命名参数的名称是动态的,支持任何合法的 URL 字符串作为参数名、支持多命名定义:/XXX/:命名/:命名/XXX
  • 命名参数的值存储在 req.params 对象中,且与res.query 不冲突:/XXX/:命名/:命名/XXX?a=1&b=2 合法✅

路由命名 ≠ RESTFUL编码风格: 不小心经常搞混他们~ (((φ(◎ロ◎;)φ))) ~

Express 命名参数: 主要用于捕获URL中动态部分,提供一种灵活的路由处理方式;

RESTful 风格: 是一种更全面的 API 设计原则,包括统一的资源命名、清晰的HTTP方法使用等,强调简洁性、可伸缩性和易于理解性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- 相同的 路由路径,不同的请求方式,处理不同的结果
- 获取所有用户:GET /users
- 获取单个用户:GET /users/{userId}
- 创建用户:POST /users
- 更新用户:PUT /users/{userId}
- 删除用户:DELETE /users/{userId}
获取请求体

Express 中获取请求体,需要使用中间件来解析请求体,不了解中间件:[闪电学习](#Express 的中间件🚻)✨ 使用body-parser中间件来解析请求体:

body-parser 是Express 框架的一个中间件,用于解析HTTP请求体,使在处理 POST 请求时够方便地获取请求体中的数据;

Express 4.16.0 版本之后,body-parser 已经不再是 Express 的依赖模块,而是需要单独安装:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install body-parser

安装了 body-parser,你就可以在 Express 应用程序中使用它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** Express获取请求体:*/
//导入express模块|创建应用对象
const express = require('express');
const app = express();

//导入body-parser模块;
const bodyParser = require('body-parser');
//根据模块创建中间件函数;
let jsonParser = bodyParser.json();                         //处理JSON格式请求体的中间件函数
let urlParser = bodyParser.urlencoded({extended:false});    //处理querystring格式请求体的中间件函数
															//(建议)false——querystring解析 | true——三方库解析
//定义路由 并绑定处理请求体的中间件:
//解析JSON格式的请求体,将其转换为JavaScript对象——>至:request.body 
app.post('/login', jsonParser, (request,response)=>{         //建议使用POST请求+接口测试工具进行测试设置请求
    console.log(request.body.username);
    console.log(request.body.userpass);
    response.send('获取请求体数据');
});

//解析表单:`application/x-www-form-urlencoded`请求体数据,转换为JavaScript对象——>至:request.body
app.post('/login2', urlParser, (request,response)=>{
    console.log(request.body.username);
    console.log(request.body.userpass);
    response.send('获取请求体数据');
});

//监听端口、启动服务: 
app.listen(5400, ()=>{ console.log('服务已经启动, 端口监听为 5400...'); });
  • POST login请求: http://127.0.0.1:5400/login 发送JSON请求:{"username":"wsm","userpass":"540"}
  • POST login2请求: http://127.0.0.1:5400/login2 解析表单application/x-www-form-urlencoded请求体数据,key-v匹配获取JavaScript对象;

关于 body-parser 模块使用/注意事项📑:

有的宝~为了方便,可以将上述的中间件,直接放进全局,这样在路由回调中就可以直接使用了;

body-parser 模块可用于创建多种请求规则解析请求体数据的中间件,包括:URL 编码JSON 数据以及多部分数据(比如文件上传 ...

  • 解析 URL 编码的请求体: 通过 bodyParser.urlencoded() 函数中间件, 可以解析 application/x-www-form-urlencoded 格式的请求体数据,将其转换成 JavaScript 对象,方便在 Express 路由中进行处理
  • 解析 JSON 格式的请求体: 通过 bodyParser.json() 函数中间件,可以解析 JSON 格式的请求体数据,将其转换成 JavaScript 对象
  • 解析多部分数据(如文件上传: 通过 bodyParser.multipart() | bodyParser.raw() ,解析多部分数据格式 文件请求体数据
  • 处理文本格式的请求体数据: 通过 bodyParser.text() 函数,解析文本格式的请求体数据
文件上传☁️

Express 文件上传: 文件上传很多项目几乎都需要,也有很多中解决方案:body-parsermulterformidable(本次使用)

formidable 是另一个常用的处理文件上传的 Node 模块,它是一个功能强大,用于解析 multipart/form-data 类型的表单数据,包括文件上传;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#安装 formidable 模块:
npm install formidable

文件上传案例:

  1. 导入formidable模块:需解构赋值获得内部对象;
  2. 表单请求的路由定义中:通过formidable模块对象,创建对应的表单对象进行解析表单参数;如果是文件需要设置:multiples: true
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** Express 文件上传:*/
//导入express模块|创建应用对象
const express = require('express');
const app = express();

//导入formidable模块;
const {formidable} = require('formidable');

//文件上传
app.post('/unloadFile',(req,res)=>{
    //创建form表单对象
    const form = formidable({ multiples: true });     //表示接收的表单是带文件的;
    //使用表单对象解析请求报文
    form.parse(req,(err,fields,files)=>{
        //表单解析错误响应
        if (err) { return res.status(500).json({ error: err.message }); }
        console.log(fields);	//普通表单:{x:[y],x2:[y2]}
        console.log(files);		//文件表单类型,支持多文件上传: { Xxx:[PersistentFile{...}],Xxx:[PersistentFile{...}], }
        res.send("成功!!");
    })
})

//监听端口、启动服务: 
app.listen(5400, ()=>{ console.log('服务已经启动, 端口监听为 5400...'); });
  • Postman 工具发送multipart/form-data类型请求: (支持多文件|属性同时上传
  • 表单对象解析 req请求对象: err:表单解析错误信息fields:普通表单类型的参数files:文件类型表单接收的参数对象

指定上传路径: 🆗上述代码外面可以通过formidable解析获取到表单文件对象,实际开发中就需要我们手动的保存文件至指定位置——通过FS模块;

而:formidable的好处可以,定义表单对象时对文件类型,指定默认服务器存储位置: 实现更方便的文件上传操作;

原始 FS模块保存文件路径: 这里宝贝需要注意,因为可能会有版本问题导致 Files参数中的属性名不一致,导致会有问题 本次3.5^版本;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//导入formidable模块;
const {formidable} = require('formidable');
const fs = require('fs');
//文件上传
app.post('/unloadFile',(req,res)=>{
    //创建form表单对象
    const form = formidable({ multiples: true });     //表示接收的表单是带文件的;
    //使用表单对象解析请求报文
    form.parse(req,(err,fields,files)=>{
        //表单解析错误响应
        if (err) { return res.status(500).json({ error: err.message }); }
        console.log(fields);	//普通表单:{x:[y],x2:[y2]}
        console.log(files);		//文件表单类型,支持多文件上传: { Xxx:[PersistentFile{...}],Xxx:[PersistentFile{...}], }

        //使用FS模块保留文件上传:
        const img = files.img[0];    //获取files对象中文件
        const filePath = img.filepath;  // 临时文件路径:表单解析上传的文件会有一个默认存放路径;
        const newFilePath = __dirname+'/images/'+img.originalFilename; //定义设置拼接保存的新文件路径 name表示文件名;
    
        fs.rename(filePath, newFilePath, (err) => {             //FS将临时路径文件——转存至——新文件路径地址;
            if (err) { return res.status(500).json({ error: err.message }); }
            res.status(200).json({ message: 'File uploaded successfully' });
        });
    })
})

formidable 表单配置设置上传路径: 3.5^版本,使用前要确保文件夹存在;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//文件上传 formidable配置上传
app.post('/unloadFile2',(req,res)=>{
    //创建form表单对象
    const form = formidable({ 
        multiples: true,
        keepExtensions: true,   //保持文件后缀
        uploadDir: __dirname + '/images', //设置上传文件的保存目录
    });
    //使用表单对象解析请求报文 甚至可以不进行解析直接保存文件上传;
    form.parse(req,(err,fields,files)=>{
        //表单解析错误响应
        if (err) { return res.status(500).json({ error: err.message }); }
        res.status(200).json({ message: '数据库保存文件路径...等后期信息;' });
    })
})

对于文件,还有很多操作,文件解析… 这里仅仅简单介绍一下,如开发遇见还需要不断学习深入💪💪💪

获取响应报文参数:

和请求报文一样,Express 提供了更方面操作响应报文的API 且,兼容原生Node

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//定义服务路由: 
app.get('/response', (req,res)=>{
    //Node原生设置响应报文
    // res.setHeader('content-type','text/html;charset=utf-8');    //解决中文乱码;
    // res.statusCode = 200;
    // res.statusMessage = 'response success';
    // res.setHeader('wsm','540');
    // res.write('write');
    // res.end('会中文乱码');

    //Express API设置响应报文
    // res.status(200);
    // res.set('wsm','540');
    // res.send('中文响应不乱码');     //Express提供send响应默认设置:UTF-8;

    //Express 支持链式编程
    res.status(200).set("header","wsm540").send("send 默认UTF-8编码格式");
})
  • res.write()、res.end 总是成对出现,且 必须调用res.end()结束请求,否则浏览器会一直处于处于请求状态 end() 不支持多行|默认中文乱码
  • res.write() 仅支持输出字符|Buffer类型,纯数值则报错,在结束浏览器响应请求之前,允许多次调用;
  • res.send() 只能被调用一次,因为它等同于res.write+res.end(),支持换行|多种内容格式的输出;
响应文件内容

Express 中,你可以使用 res.sendFile("文件路径") 方法可以向客户端发送文件

指定文件的路径,Express 将自动设置正确的 Content-Type 并发送文件内容给客户端,设置响应文件:resFile.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        /* CSS样式来将标题居中 */
        body {
          display: flex;
          justify-content: center;
          align-items: center;
          height: 100vh;
          margin: 0;
        }
      </style>
</head>
<body>
    <h1>Express 文件响应!!!</h1>
</body>
</html>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** 特殊响应: */
//Path系统路径模块
const path = require('path');   
//响应文件内容
app.get('/resFile',(req,res)=>{
    //Express 使用 res.sendFile() 向客户端直接响应文件内容;
    res.sendFile(path.resolve()+"/resFile.html");       //支持使用 path.resolve 绝对路径拼接;
})

浏览器请求: http://127.0.0.1:5400/resFile 则直接响应 resFile.html文件内容;

重定向响应

Express 中,你可以使用 res.redirect("重定向地址") 方法来发送重定向响应

方法会向客户端发送一个 HTTP 重定向状态码(默认是 302 Found)以及一个 Location 头部,告诉客户端去请求另一个 URL

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//重定向响应
app.get('/resRedirect',(req,res)=>{
    //Express 使用 res.redirect() 进行重定向响应;
    res.redirect("https://www.bilibili.com/");  //重定向至 B站
})

重定向 和 转发: 说到重定向不得不提的就是转发,Express并没有针对转发的API,不过可以通过三方API实现;简单介绍一下:

  • 重定向: 是一种服务器端行为,它会告诉客户端浏览器请求的资源已经移到了其他位置,需要重新发起一个新的请求去获取这个资源 服务器会发送一个带有重定向状态码(通常是 3xx)的响应,并在响应头中包含一个新的URL地址,告诉浏览器去请求这个新的URL :浏览器会发送两次请求,URL会发生改变,重定向没有限制,任何web资源(包括网络上的web资源)
  • 转发: 转发是一种服务器内部的行为,客户端请求服务器——服务器内重新请求并响应结果传递给客户端,客户端无感中间过程接收响应; :浏览器仅发送一次请求,URL不会发生改变,转发只限制在当前web项目中,转发由于是同一个请求,所以request域不变

⚙️⚙️应用场景:

  • 重定向: 常用于将用户导航到不同的URL,比如用户登录后重定向到首页,或者在资源经常移动或删除前端无法固定地址的重定向页面;
  • 转发: 常用于在同一个程序内部不同组件之间传递请求和响应对象,比如在MVC架构中,控制器可以处理请求并将请求转发到对应的视图来渲染页面;
JSON响应

在 Express 中响应 JSON 数据非常简单,使用 res.json(“{JSON:'字符串'}”) 方法进行 JSON 格式的响应

方法会自动设置适当的 Content-Type:application/json; charset=utf-8,并将 JSON响应客户端

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//JSON向响应
app.get('/resJson',(req,res)=>{
    //Express 使用 res.redirect() 进行重定向响应;
    res.json({ wsm:540, age:18, });  //重定向至 B站
})
下载响应🗂️

在 Express 中可以使用 res.download('文件路径','下载文件名',(异常回调函数)=>{...})

来发送文件下载响应,这个方法指定的文件作为附件发送给客户端,浏览器触发文件下载操作⬇️🗂️

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//下载响应
app.get('/resDownload',(req,res)=>{
    //Express 使用 res.redirect() 进行重定向响应;
    res.download(path.resolve()+"/resFile.html",'测试下载文件.html',(err)=>{
        if(err){
            console.error('File download failed:', err);    //文件下载异常!
            res.status(500).send('Internal Server Error');
        }else{ console.log('File download successful'); }   //文件下载成功!
    });
})

Express 的中间件🚻

Express 的中间件本质是一个回调函数Middleware

主要目的是处理 HTTP 请求,对请求进行预处理、执行一些操作,将请求next 传递——》下一个中间件或路由处理程序:

中间件允许你以模块化的方式组织你的 Express 应用程序,将应用程序拆分成小的、可复用的部分,使得代码更加清晰和易于维护

  • 中间件类型: 全局中间件路由中间件静态资源中间件
  • 和路由的回调函数一样,也具有:requerstresponse 参数对象;
  • Express 中间件的主要作用: 处理公共 HTTP 请求和响应、执行一些操作,如身份验证、日志记录、数据解析等 ···

编程web领域很多语言都有中间件的概念可能叫法不同: Java-servlet的过滤器、Spring的拦截器 ··· 本质原理概念都一样;

全局中间件:

全局中间件是在 Express 应用程序中的,每个请求上执行的中间件: 这意味着它们会影响到应用程序中的每个路由;⬇️⬇️定义全局路由:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//1.定义全局中间件函数:
let allMiddleware = function(request,response,next){
    //函数本质就是一个普通函数,三个参数:请求对象、响应对象、next指向下一个中间函数|路由回调;
    //函数内执行|过滤···每一个请求路由都会进入这里,最后:next(); 执行路由...
}
//2.绑定至Express全局对象
app.use(allMiddleware);
//

Demo 案例: 相信很多网站都有的日志需求,网站行记录每一次请求:时间、接口、IP… 保存日志;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//通过FS模块追加指定日志文件;
const fs = require('fs');
fs.appendFileSync(path.resolve(__dirname, './access.log'), `${url}  ${ip}\r\n`);
  • 实现这个需求就是,在路由回调中添加+追加日志代码, 但对于所有路由都需要这段代码实在太冗余了所以,可以通过 全局中间件 进行统一定义:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//导入express模块、创建应用对象
const express = require('express');
const app = express();

/** 定义全局路由: */
//1.定义全局中间件:
const fs = require('fs');       //导入需要的模块
const path = require('path');
let allMiddleware = function(request,response,next){
    let {url, ip} = request;    //解构赋值获取参数
    fs.appendFileSync(path.resolve(__dirname, './access.log'), `${url}  ${ip}\r\n`);    //FS追加写入文件;
    //最后 next() 执行下一个中间件|路由回调函数;
    next();
}
//2.绑定Express全局对象: 支持箭头函数声明: app.use((req,res,next)=>{....});
app.use(allMiddleware);
app.use((req,res,next)=>{console.log("中间件1"); next(); });
app.use((req,res,next)=>{console.log("中间件2"); next(); });

//定义服务路由: 
app.get('/demo', (req,res)=>{ res.end('Hello ExpressServer'); })
app.get('/demo2', (req,res)=>{ res.end('Hello ExpressServer'); })

//监听端口、启动服务: 
app.listen(5400, ()=>{ console.log('服务已经启动, 端口监听为 5400...'); }); 
  • 上述代码,无论浏览器如何请求: http://127.0.0.1:5400 都会进行日志记录;
多全局中间件定义:

Express 允许定义多个中间件,并按声明顺序进行执行: 多中间件,本质和单中间件一样,中间件执行顺序: 与它们被添加到app.use(???)的顺序相同;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//程序自上而下: 先全局绑定的中间件先执行;
app.use((req,res,next)=>{console.log("中间件1"); next(); });	
app.use((req,res,next)=>{console.log("中间件2"); next(); });
路由中间件:

路由中间件是与特定路由相关联的中间件: http://127.0.0.1:5400/demo|1|2 进行请求;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//定义服务路由: 
//与全局中间件不同,因为是针对部分路由,所以需要直接与路由进行绑定;
app.get('/demo',(req,res,next)=>{
    console.log("路由中间件");
    next();
},(req,res)=>{
    console.log("路由回调函数");
    res.end('Hello ExpressServer'); 
})

//一个中间件支持绑定多个:路由;
//一个路由也支持绑定多个:路由中间件;
let routefun1 = function(req,res,netx){ console.log("路由中间件1"); netx(); }
let routefun2 = function(req,res,netx){ console.log("路由中间件2"); netx(); }

app.get('/demo1',routefun1,routefun2,(req,res)=>{
    console.log("路由回调函数1");
    res.end('Hello ExpressServer 1'); 
})

app.get('/demo2',routefun1,routefun2,(req,res)=>{
    console.log("路由回调函数2");
    res.end('Hello ExpressServer 2'); 
})

路由|全局中间件,本身其实都是普通的函数: (req,res,next)=>{···} 通过不同的方式进行绑定,即不同的效果;

  • 直接与路由进行绑定——路由中间件
  • 通过: app.use(???) 全局绑定——全局中间件
静态资源中间件:

静态资源中间件: 顾名思义,是Express 专门用来处理静态资源的中间件:图像、.css、.JS...

它允许你指定一个目录,该目录中的文件将被直接提供给客户端,而无需经过任何额外的处理,让 Express 自动为客户端提供这些文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//代码很简单:
//将 public 目录下的文件设置为静态资源
app.use(express.static('public'));

此时如果你有一个名为 public 的目录,并且在该目录中有一个名为 image.jpg

客户端仅需要: http://localhost:???/image.jpg 即可获取这个文件,而不需要任何额外的路由处理程序; 支持设置多静态资源目录: ⬇️

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
app.use(express.static('静态资源目录1'));
app.use(express.static('静态资源目录2'));		//如果两个目录中都存在相同名称的文件,则优先使用定义的目录为准;

静态资源中间件——⚠️⚠️注意事项:

  • 静态资源中间件专门为响应静态资源而产生!!
  • 对于 / 路径请求,如果配置了静态资源中间件 Express会默认响应:index.html
  • 如果静态资源与路由规则同时匹配,谁先匹配谁就响应:自上而下原则,声明靠前的响应;
中间件执行顺序:
  1. 浏览器发送请求: 静态资源请求|路由请求,无论如何都会先经过全局中间件——next()
  2. 判断请求是: 静态资源请求则直接匹配对应的资源响应,路由则寻对应路由响应
  3. 路由请求: next()——路由中间件——最后,进入路由回调;
  4. 最后: response 响应浏览器页面;
⚠️⚠️中间件的注意事项:

Express 代码严格遵循自上而下执行,即:全局中间件,建议定义在路由的前面 则,请求匹配先匹配到路由则不会执行 全局中间件!!!

中间件的Next() 指向下一个中间件|路由回调: 要确保代码中next() 函数的正确使用!!!

静态资源中间件: 默认对/ 请求匹配 /index.html 如与路由冲突,遵循先入为主原则!!!

Express 路由模块化🧊

模块化的概念: 想必大家都知道:将一个大的功能拆分多个小的模块,最后组合在一起,方便管理维护;

路由模块化: 实际开发中一个项目,会有很多路由,如果都定义在一个配置文件中,那么根本不敢想象,无敌的臃肿冗余、不方便维护;

  • 路由的模块化是一种良好的做法,它使得代码结构更清晰、易于维护,并且便于团队协作;
  • 可以通过将路由处理程序分解为单独的模块,然后在应用程序中引入和使用这些模块来实现路由的模块化

路由模块化Demo:

这里有的宝贝,可能会疑惑❓为什么是 use() 不是定义中间件的吗? 不要固化!use() 不仅仅是引入中间件;

实际上,app.use() 是一个非常通用的方法,它用于将中间件绑定到应用程序的路径上,以及将路由绑定到应用程序的路径上

中间件和路由实际上都可以被认为是一个可以处理请求的处理函数,按定义顺序绑定到,程序请求路径上:

所以: 使用Express 一定要注意代码的编写顺序~~,不然可能会有想不到的bug🐞🐞

module1.js 模块: 定义商品的API路由模块;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** Express路由模块化:*/
//1.导入express模块
const express = require('express');

//2.创建路由对象
const router = express.Router();        //路由对象其实就相当于 小型的app应用对象 const app = express();
//3.路由对象定义路由:
router.get('/commodity', (req, res) => { res.send('查询商品'); })       //查询商品
router.get('/commodityID', (req, res) => { res.send('查询固定商品'); }) //查询固定商品

//4.对外暴露路由对象:
module.exports = router;

module2.js 模块: 定义购物车的API路由模块;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//导入express模块
const express = require('express');

//创建路由对象
const router = express.Router();
//路由对象定义路由:
router.get('/shopcart', (req, res) => { res.send('查询购物车'); })          //查询购物车
router.get('/shopcartCom', (req, res) => { res.send('查询购物车商品'); })   //查询购物车商品

//对外暴露路由对象:
module.exports = router;

mainApp.js 程序主文件: 启动程序,仅需要 node mainApp.JS 一个文件即可运行所有定义的路由请求;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** Express模块化主文件:*/
//导入express模块|创建应用对象
const express = require('express');
const app = express();

//1.引入子路由文件
const commodity = require('./module1');
const shopcart = require('./module2');
//2.设置和使用中间件:
app.use(commodity);
app.use(shopcart);

//监听端口、启动服务: 
app.listen(5400, ()=>{ console.log('服务已经启动, 端口监听为 5400...'); });
  • 请求: http://127.0.0.1:5400/shopcart 查询购物车、http://127.0.0.1:5400/commodity 查询商品
  • 路由前缀: app.use('/前缀',路由模块); 对于导入路由模块,支持同时设置路由前缀,来区分路由请求;
路由模块化高级⏫:

高级Express应用程序的目录结构如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
project/
|-- controllers/
|   |-- userController.js
|   |-- productController.js
|-- routes/
|   |-- userRoutes.js
|   |-- productRoutes.js
|-- app.js
|-- package.json

controllers 目录:在 controllers 目录中存放各个路由的处理程序,每个控制器模块负责处理一个或多个路由的请求和响应逻辑

routes 目录:在 routes 目录中存放路由模块,每个路由模块负责将特定路径的请求路由到相应的控制器处理程序

app.js 文件:引入和使用路由模块,并将其与 Express 应用程序关联起来

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-06-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
史上最全的黑苹果系统「MacOS」安装教程,小白也能秒掌握!
折腾过的人应该不陌生,自从苹果采用 Intel 的处理器,被解锁后可以安装在 Intel CPU 与部分 AMD CPU 的机器上。从而出现了一大批非苹果设备而使用苹果操作系统的机器,被称为黑苹果(Hackintosh)。
全栈程序员站长
2022/07/01
15.9K0
史上最全的黑苹果系统「MacOS」安装教程,小白也能秒掌握!
手把手教您组装一台家用NAS J3455黑群晖6.1.7搭建全过程[通俗易懂]
经过俺几个月的观察和尝试,最终锁定了目标:J3455处理器。将之前的蜗牛星际都换成了J3455,可以说是性能,功耗,都非常适合的一台NAS。
全栈程序员站长
2022/09/20
12.1K0
手把手教您组装一台家用NAS J3455黑群晖6.1.7搭建全过程[通俗易懂]
关于睡眠和休眠
到底用睡眠和休眠,还是直接关机的问题,争论颇多,大家各有各的观点和立场。实际上在很长一段时间内我本人的态度也是变化了不少,在此我想说说我对这个问题的看法,简要分析一下可能涉及到的几个方面。这只是我个人的观点,欢迎大家发表不同意见,但回帖前请先完整的看完本帖的内容。 我首先给出结论,我认为:在大部分情况下使用睡眠和休眠就可以了,重启和关机是在极少数情况下使用的,比如安装了新软件要求重启,或者系统出现了严重故障。下面从几个方面来说这个问题,这里默认了一个前提,就是你的主板支持 s3 待机。究竟哪些主板支持?我家有台老爷机, 2001 年买的,它都支持,我想不必再多说些什么了吧,有的主板需要在 bios 里开启后才支持。还有一种判定方法,就是在设备管理器的系统设备里,看看有没有个叫 "ACPI-Compliant System" 的东西,如果有的话就说明高级电源管理接口已经启动,即支持 s3 待机。
williamwong
2018/07/24
3K0
关于睡眠和休眠
树莓派4b基础入门「建议收藏」
树莓派(Raspberry Pi)是一款基于ARM的微型电脑主板,旨为学生计算机编程教育而设计,其系统基于Linux,由注册于英国的慈善组织“Raspberry Pi基金会”开发,Eben·Upton为项目带头人。别看其外表“娇小”,内“心”却很强大,上网、看视频、听音乐等功能都有,可谓是“麻雀虽小,五脏俱全”。自问世以来,受众多计算机发烧友和创客的追捧。 1.树莓派的家族
全栈程序员站长
2022/07/01
7.7K0
树莓派4b基础入门「建议收藏」
操作系统是什么都没整明白,写什么代码?
现代操作系统由一个或多个处理器、主存、打印机、键盘、鼠标、显示器、网络接口以及各种输入/输出设备构成。计算机操作系统是一个复杂的系统。
淘课之家
2020/04/01
1.4K0
操作系统是什么都没整明白,写什么代码?
手把手教你安装黑苹果之openCore-0.6.3 EFI制作全过程,非常详细
这篇文章主要是记录自己动手安装Big Sur在过程,和心理。略显繁琐,请自行跳跃观看。
全栈程序员站长
2022/09/12
22.9K0
手把手教你安装黑苹果之openCore-0.6.3 EFI制作全过程,非常详细
计算机基础(二)
计算机基础(二) 设计架构     一般消费者常说的电脑通常指的就是x86的个人电脑架构。早期两大主流x86开发商(Intel, AMD)的CPU架构与设计理念都有些许差异。 1、CPU 1.Intel芯片架构     北桥:负责链接速度较快的CPU、内存与显卡接口等元件。     南桥:负责连接速度较慢的设备接口,包括硬盘、USB、网卡等等。     由于北桥最重要的就是CPU 与内存之间的桥接,因此目前的主流架构中,大多将北桥内存控制器整合到CPU封装当中了。     早期芯片组分南北桥,北桥可以连接C
云飞扬
2018/06/19
1.5K0
你越没钱越需要精打细算 (设计师电脑购买指南)
作为一名设计师,有时候真的在想为什么要选择这个行业,经常性的加班已经让人身心俱疲,加班越来越多,电脑配置越来越高, 但是工资却还是不见长!
用户1730674
2020/01/02
5.3K0
教你不花一分钱,用十分钟把旧电脑打造成自己的Windows版NAS系统
一年前我前前后后花了2个多星期的时间才将整套系统部署完成,但这是因为其中有很多的坑,需要找到解决方案。我已经尽可能把过程中遇到的所有问题都写明,大家只要跟着去做,还是非常简单的,不需要太长时间。整套系统至今一直非常稳定。
ICT系统集成阿祥
2024/12/30
11.8K0
教你不花一分钱,用十分钟把旧电脑打造成自己的Windows版NAS系统
OC简要配置说明(旧)已修正
注意事项:OC对于有依赖的SSDT/KEXT加载顺序有严格要求,注意在config配置中的顺序。 主要适用于UEFI启动的电脑。 本文当前写作时OC正式版为0.5.9,0.6.0测试版。以下的配置适用于这两个版本,后续OC的更新可能会有些许改动,到时候应该再参考官方文档进行修改。
GOOPHER
2022/03/31
8.6K0
OC简要配置说明(旧)已修正
常用电脑资料速查
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/10
2.5K0
黑群晖安装和使用的常见问题及解决办法【不定期更新中】
答:群晖系统跟Windows不同,Windows有个盘要当成系统盘,而群晖会在每个硬盘上自动安装系统。每个硬盘?对,没错,就是每个硬盘。比如你是6盘位,接了6个硬盘,这6个硬盘初始化以后,每个硬盘都有系统了。所以拿一个SSD来做系统盘的这个做法没必要。当然,也有全部用SSD的土豪,那就不是这个话题了。
cnlixs
2022/11/01
60.5K2
黑群晖安装和使用的常见问题及解决办法【不定期更新中】
廉价的全闪存雷电 NAS 折腾笔记:NUC9 操作系统踩坑
我使用的设备是 NUC9i5QNX,这台设备的硬件基础规格,可以在 Intel ARK 网站中找到。在上一篇文章《廉价的全闪存雷电 NAS 折腾笔记:组网方案的选择》中,我介绍了这台设备的优势,感兴趣可以自行翻阅。
soulteary
2023/09/12
3.3K1
廉价的全闪存雷电 NAS 折腾笔记:NUC9 操作系统踩坑
关于选购笔记本电脑
与电脑打交道十多年来,以及从事程序数年转网络安全三年来,在与985空间安全研究生、电脑经销商,网络安全实验室负责人、讨论及对购买电脑的理解,写下此文。
中龙技术
2022/09/29
4.7K0
关于选购笔记本电脑
Windows操作系统基础
行业介绍 操作系统:Linux系统 Windows系统 Linux系统是80%企业使用的服务器,Windows更适合个人电脑。 为什么企业都用Linux系统:①开源 ②免费 ③安全 ④稳定
张哥编程
2024/12/13
2010
个人计算机硬件设备配置介绍与选型参考
描述:在我们日常使用的计算机中除了需要有硬件支持,还需要要有软件支持,比如我们的操作系统; 在我们自己安装系统或者DIY笔记本电脑的时候需要购买一些PC的一些周边硬件,当然您需要对其有一个大致的了解,所以本篇文章给计算机小白们一个基础入门;
全栈工程师修炼指南
2022/09/28
3.4K0
个人计算机硬件设备配置介绍与选型参考
写给大忙人看的操作系统
现代计算机系统由一个或多个处理器、主存、打印机、键盘、鼠标、显示器、网络接口以及各种输入/输出设备构成。
cxuan
2020/03/04
8360
写给大忙人看的操作系统
Linux系统安全加固指南(万字长文)
本指南旨在说明如何尽可能地加强Linux的安全性和隐私性,并且不限于任何特定的指南。
肉眼品世界
2022/04/19
7K0
硬件资料和软件资料_电脑硬件检测工具哪个好
2. BIOS报警声意义 3. BIOS自检与开机故障相关问题 5. 计算机几个常见指标的意义 6. 显卡GPU参数 7. 显示卡常见故障全面解决 8. 集成声卡常见故障及解决 9. 显示器经典故障以及处理办法 10. AMI主板代码大全(BIOS-ID)
全栈程序员站长
2022/11/01
4.9K0
推荐阅读
相关推荐
史上最全的黑苹果系统「MacOS」安装教程,小白也能秒掌握!
更多 >
LV.7
腾讯云产品运营
目录
  • NodeJS背后的人:Express
    • Express
    • Express使用🚀:
    • Express路由🌐:
    • 获取请求报文参数:
      • URL路由命名参数:
      • 获取请求体
      • 文件上传☁️
    • 获取响应报文参数:
      • 响应文件内容
      • 重定向响应
      • JSON响应
      • 下载响应🗂️
    • Express 的中间件🚻
      • 全局中间件:
      • 路由中间件:
      • 静态资源中间件:
      • 中间件执行顺序:
      • ⚠️⚠️中间件的注意事项:
    • Express 路由模块化🧊
      • 路由模块化Demo:
      • 路由模块化高级⏫:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档