Node.js笔记-Express(基于Node.js的web开发框架)

news2024/12/30 2:43:47

目录

Express概述

Express安装

基本使用

创建服务器 

编写请求接口

 接收请求参数

 获取路径参数(/login/2) 

 静态资源托管-express.static(内置中间件)

什么是静态资源托管?

express.static()

应用举例

 托管多个静态资源

挂载路径前缀

 工具:nodemon (自动动态重启项目)

概述

安装

使用 

Express路由

什么是路由?

路由的组成

路由映射规则

 模块化路由

 Express中间件

概述 

 Express中间件的定义

中间件的使用(全局注册)

定义多个全局中间件以及简化写法

定义局部中间件

错误级别中间件(用于异常处理)

 Express内置中间件(express.static()...)

 解析请求时携带的请求体数据和json数据(使用内置中间件) 

跨域资源共享 CORS(Cross-Origin Resource Sharing)

概述 

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


Express概述

 Express官网自述:基于Node.js平台快速,灵活,极简的web框架。

Express本质上是Node.js的一个包,它封装了http模块的功能,可以看作是http模块的一个框架,使用Express框架做web开发使得开发更加快速,简单且高效。

我们使用Express框架一般用于创建web服务器,且编写后端请求接口。 

Express安装

因为Express本质是Node.js的一个第三方包,所以需要使用npm 进行包的下载

 安装命令 npm i express 

基本使用

创建服务器 

 需求:使用Express框架创建一个web服务器。

// 1.导入express的包
const express = require("express");

// 2.创建web服务器实例
const server = express();

// 3.设置端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功,运行在88端口!");
})

至此一个最简单的服务器就创建好了,我们可以通过浏览器输入URL访问此服务器。但是此服务器并没有对外提供接口,我们下面就书写接口供请求访问。

编写请求接口

 格式 服务器实例.请求方式("请求路径",回调函数) ,例如:

server.get("/login",(request,response)=>{

        console.log("请求成功!") // 控制台提示

        response.end("请求成功"); // 向页面响应并结束本次请求

})​​​​​​​

参数:

request:请求对象,获取请求时的属性或参数

response:响应对象,向页面响应数据,结束请求。

 需求 :编写一个get请求方式,路径为/login的接口, 以及一个相同路径,但是为post请求方式的接口。两个接口都给前端响应一些提示。

// 导入express的包
const express = require("express");

// 创建web服务器实例
const server = express();

// 编写get请求方式的接口,请求路径为/login
server.get("/login",(request,response)=>{
    // 控制台提示
    console.log("访问接口=>/login");
    //设置字符集,防止响应时乱码
    response.setHeader("Content-Type","text/html; charset=utf-8")
    // 给前端页面响应数据
    response.end("正在访问登录接口!请求方式为:get")
})

// 编写post请求接口,请求路径为/login
server.post("/login",(request,response)=>{
    // 控制台提示
    console.log("访问接口=>/login");
    // 给前端页面响应数据
    response.end("正在访问登录接口!请求方式为:post")
})


// 设置端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功,运行在88端口!");
})

 测试 :由于我们通过浏览器访问请求方式默认都是GET请求,所以我们使用post进行接口测试。

 ​​​

 

 接收请求参数

获取URL路径中参数 (/login?name=a)

我们使用回调函数的第一个参数request来调用query对象就能够输出前端传入的参数

值得注意的是:使用request.query只能够接收写在请求路径中的参数

// 导入express的包
const { query } = require("express");
const express = require("express");

// 创建web服务器实例
const server = express();

// 编写get请求接口,请求路径为/login
server.get("/login",(request,response)=>{
    // 控制台提示
    console.log("访问接口=>/login");
    //设置字符集,防止响应时乱码
    response.setHeader("Content-Type","text/html; charset=utf-8")

    //获取请求参数
    const agesReq = request.query;
    // 给前端页面响应数据
    resStr = "正在访问登录接口!请求方式为:get\n请求参数为:" + agesReq.name;
    response.end(resStr)
})

// 设置端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功,运行在88端口!");
})

 接口测试: 

 获取路径参数(/login/2) 

不需要写属性名,直接在/符号后写值,后端也能接收到。

// 导入express的包
const { query } = require("express");
const express = require("express");

// 创建web服务器实例
const server = express();

// 编写接口
server.get("/login/:id/:name",(request,response)=>{
    // 接收路径参数
    console.log(request.params);
    resArgs = "路径参数为,id=>" + request.params.id +
                "name=>"+ request.params.name
    response.end(resArgs);
})

// 设置端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功,运行在88端口!");
})

还有例如前端传入的数据是json数据,以及是请求体中的数据,我们现在还不能接收,因为node默认不能直接接收需要使用中间件,但是我们没有了解中间件,我们需要使用中间件处理后我们才能接收到这些特殊的参数。在下方会对中间件以及特殊参数的接收作说明。

 静态资源托管-express.static(内置中间件)

什么是静态资源托管?

我们通过前端请求,例如请求/login.html,我们就需要向页面展示login.html页面,这个向页面展示我们本地的静态资源的功能托管,就叫做动态资源托管。只要前端访问相应路径,那么就会自动向前端页面去展示静态资源。

express.static()

静态资源托管这个动作,需要我们调用express.static(),所以我们知道在static()中做了一些事情可以自动帮助我们进行静态资源的展示但是这个static()函数在什么时候调用呢?需要我们手动调用么?

其实,对于static函数的执行时机,我们想要当请求访问静态资源的时候去自动的调用

那么当请求来的时候自动调用,可以帮我们做这件事的就是中间件机制。所以说,static()其实就是express的一个内置中间件

中间件简单描述:当请求一发过来,那么首先进入的是中间件进行处理,在带着处理好的内容进入我们的路由处理函数中间件注册方式:服务器实例.use()

ps:对于中间件的讲解,下面会说到,在此简单提及。

应用举例

需求:将html目录下的静态资源进行托管。

// 导入express的包
const express = require("express");

// 创建web服务器实例
const server = express();

// 将html目录下的静态资源进行托管
// 将托管静态资源内置中间件(static)进行注册,使用server.use()进行注册
server.use(express.static('html'))

// 设置端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功,运行在88端口!");
})

 我们通过浏览器访问 

 值得注意的是

我们通过URL访问静态资源,可以忽略掉static("")中定义的托管目录进行访问。

 托管多个静态资源

需要托管几个目录,那么就注册几次中间件就行。 

// 托管资源目录html
server.use(express.static('html'))
// 托管资源目录css
server.use(express.static('css'))

挂载路径前缀

我们通过上方知道,我们在static()函数中指定的目录,在访问时是不需要指定的,但是,向上方,如果我们托管的是html目录,此目录下是html页面,那么其实我们还是想要通过html目录去访问的,例如:html/login.html,这样可以使访问路径更清晰。

 写法  

// 将html目录下的静态资源进行托管
server.use("/html",express.static('html'))

 访问  

 工具:nodemon (自动动态重启项目)

概述

在我们没有使用此工具前,我们的后台代码只要修改,那么我们就要去重启服务器,非常繁琐,所以此工具就能解决这样的问题,只要我们保存代码,那么我们不需要重启就能访问最新状态

安装

npm install nodemon -g 

使用 

 在启动项目的时候,我们把原来的node命令换成nodemon即可。后面就不需要手动重启项目了。

Express路由

什么是路由?

在express中,路由可以说是一种映射关系,谁映射谁呢?

就是前端请求映射后端请求处理函数。

通过路由,前端发来不同请求,我们都会调用不同的处理函数进行分别处理。

路由的组成

路由分别由:请求方式,请求路径,处理函数构成。

路由映射规则

会根据请求方式和请求路径来判断交给哪个处理函数进行处理

例如:请求方式get路径/login 和 请求方式post 路径/login

两个虽然路径相同但是是交给两个不同的处理函数进行处理的。

 模块化路由

为什么需要将路由模块化?

想个场景:我们一个网站有多个模块,例如有user(用户信息)模块和goods(商品信息)模块,每个模块中的接口(路由)是比较多的,如果我们都将接口(路由)写在一个页面,那么将造成可读性变差的问题。

对于这个问题,我们就可以将路由模块化,我们单独创建一个文件,可以将单个文件单独来处理一个前端的小模块(例如用户信息模块)发来的路由。这样前端有多少个模块,那么我们就定义多少个路由模块,这样管理和编写起来就会方便许多

需求:定义一个文件,专门用来处理/login(登录模块)的路由。

// 导入express的包
const express = require("express");

// 创建路由对象实例
const router = express.Router();

// 添加路由
// 添加用于登录时处理的路由
router.get("/logins/login",(request,response)=>{
    response.setHeader("Content-Type","text/html; charset=utf-8")
    response.end("登录成功!");
})

// 添加用于注册时处理的路由
router.get("/logins/register",(request,response)=>{
    response.setHeader("Content-Type","text/html; charset=utf-8")
    response.end("注册成功!");
})

//将路由对象暴露(共享)出去,给主文件引入
module.exports = router;

 主文件注册路由 

// 导入express的包
const express = require("express");

// 创建web服务器实例
const server = express();

// 导入自定义路由模块
const myRouter = require("./loginRouter")

// 将路由进行注册,服务器启动后将可以访问模块中的路由
server.use(myRouter)

// 设置端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功,运行在88端口!");
})

 测试模块化路由  

 Express中间件

概述 

对于中间件,上方我们已经使用过了一次,就是静态资源管理。那么什么是中间件呢?

就是业务流程中的处理环节

例如:我们在流水线上班,一个零件需要经过8道工序,那么从开始到结束,我们中间这8道工序就是中间处理环节,也就是中间件。

在Express中的例子:我们一个请求处理的流程是:发来请求,路由映射处理,将处理后的结果响应出去。那么现在有一个需求,就是当请求发来的时候,我们先不让请求进入路由进行映射,而是先检查当前的请求是否符合我们的要求,如果符合就放行此请求,否则就拦截。

在这个案例中,中间件就在请求过程中充当了中间检查的角色,其实我们只要设置了中间件,那么请求就是会自动先进入一个或多个中间件接收处理,处理好了再进入路由的

中间件的本质就是一个有着固定参数的函数

function(request, response, next){

        //函数体

}

request:请求对象

response:响应对象

next:连接函数,用于连接下一个中间件或路由(必要执行)

 在多个中间件之间,共享着一份request和response,类似单线程,是参数共享传递。

 Express中间件的定义

//创建中间件
const mw = function(request,response,next){
    console.log("中间件正在处理...");
    //一定要调用next(),否则中间件的传递将断开
    next()
}

中间件的使用(全局注册)

 需求 :定义一个中间件,当请求发来时,在此中间件中打印一些信息,之后再交给路由处理。

// 导入express框架
const express = require("express");

// 创建服务器实例对象
const server = express();

/**
 * 定义一个中间件
 * @param {*} request 请求对象
 * @param {*} response 响应对象
 * @param {*} next 传递函数,执行函数代表此中间件处理完毕传给写一个中间件或路由
 */
const mw = function(request,response,next){
    console.log("中间件正在处理...");
    next()
}

// 注册中间件(全局注册)
server.use(mw);

// 创建一个路由接收中间件,并处理请求
server.get("/login",(request,response)=>{
    console.log("请求已到达路由进行处理...");
    response.setHeader("Content-Type","text/html; charset=utf-8")
    response.end("中间件测试");
})

// 设置监听端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功!运行在88端口。");
})

我们向/login发送请求,终端输出: 

定义多个全局中间件以及简化写法

 // 定义第多个中间件 (server是服务器实例对象

server.use((request,response,next)=>{

    console.log("我是第1个中间件...");

    next()

})

server.use((request,response,next)=>{

    console.log("我是第2个中间件...");

    next()

})

server.use((request,response,next)=>{

    console.log("我是第3个中间件...");

    next()

})

........

说明 :在上方的中间件定义中,全部采用的是全局的注册方式,也就说,我们访问任何路由都会经过这些全局中间件,那么有时候我们会有这样的需求:让某个中间件仅仅处理某个路由的请求,这是可以实现的,我们就中间件注册成局部的即可(定义在路由上)。

定义局部中间件

 // 定义一个局部中间件仅服务于单个路由(第二个参数mw为定义好的中间件

server.get("/login",mw,(request,response)=>{

    console.log("正在访问:",request.url);

})

完整代码

// 导入express框架
const express = require("express");

// 创建服务器实例对象
const server = express();

// 定义一个中间件,待会儿局部注册
const mw = function(request, response, next){
    console.log("中间件正在处理...");
    next();
}

// 定义一个局部中间件仅服务于单个路由
server.get("/login",mw,(request,response)=>{
    console.log("正在访问:",request.url);
})

// 设置监听端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功!运行在88端口。");
})

给一个路由定义多个中间件的方式

// 定义多个局部中间件仅服务于单个路由

server.get("/login",[mw1,mw2,mw3....],(request,response)=>{

    console.log("正在访问:",request.url);

})

get的第二个参数为可变形参,可以接收多个参数,或者接收一个数组,里面存放着我们想要进行多个局部注册的中间件。

错误级别中间件(用于异常处理)

当我们的程序发生错误的时候,那么如果我们不自己进行错误捕获处理,那么前端就会报如下错误,并不是那么的友好。

 所以我们应该去捕获后端发生的异常,并且进行处理,并且给前端一些友好提示。

 处理以后的页面提示

// 导入express框架
const express = require("express");

// 创建服务器实例对象
const server = express();

// 创建一个路由接收中间件,并处理请求
server.get("/login",(request,response)=>{
    //手动抛出一个异常,测试错误级别中间件是否可用
    throw new Error("自定义异常...")
    console.log("请求已到达路由进行处理...");
    response.setHeader("Content-Type","text/html; charset=utf-8")
    response.end("中间件测试");
})

// 定义错误级别的全局中间件
server.use(function(err,request,response,next){
    response.setHeader("Content-Type","text/html; charset=utf-8")
    console.log("错误信息:",err.message);
    response.end("发生了错误...请等一等再访问..." )
})

// 设置监听端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功!运行在88端口。");
})

// 错误处理函数是有4个函数参数

function(err,request,response,next){

        // 处理函数体

}

 Express内置中间件(express.static()...)

 关于Express的内置中间件,我们在上方的静态资源托管的时候就已经使用到了,就是将内置中间件static()进行注册,接着什么都不用做,我们指定的静态资源目录就托管好了。就是内置中间件帮我们做的这些事。

3个常用的内置中间件

 ① express.static():帮助快速托管静态资源。

 ② express.json():解析请求时携带的请求体json数据。---存在版本兼容性

 ③ express.urlencoded():解析请求时请求体url-encoding格式的数据。  ---存在版本兼容性

注册方式(使用全局注册)

// 解析请求体中的json数据

 server.use(express.json())

// 解析url-encoding格式数据-固定写法

server.use(express.urlencoded({extended:false}))

 解析请求时携带的请求体数据和json数据(使用内置中间件) 

在上面讲到获取请求参数时,我们默认只能获取请求URL中的参数以及路径参数,像请求体中参数为json数据我们是接收不到的。那么我们通过内置的中间件,就可以解决请求体json数据,以及url-encoding数据接收不到的问题。

需求:接收请求时传入的请求体json数据。

// 导入express框架
const express = require("express");

// 创建服务器实例对象
const server = express();

// 注册内置中间件
server.use(express.json()) // 解析请求体中的json数据

// 创建一个路由接收中间件,并处理请求
server.get("/login",(request,response)=>{
    // 接收请求体的json数据(使用request.body接收)
    console.log("请求体参数为:",request.body);
    response.setHeader("Content-Type","text/html; charset=utf-8")
    response.end("请求体参数为:\n"+"姓名:"+request.body.name
                    + "\n年龄:"+ request.body.age);
})

// 设置监听端口并启动服务器
server.listen(88,()=>{
    console.log("服务器启动成功!运行在88端口。");
})

使用postman进行发送json数据测试 

 

跨域资源共享 CORS(Cross-Origin Resource Sharing)

概述 

作用解决跨域资源请求问题

问题说明:因为我们的浏览器一般是遵循同源安全策略的,也就是说当我们不遵循此策略,那么我们的请求将被阻止。

什么是同源安全策略?

为了保证我们的资源安全,浏览器默认接受请求条件为:

相同的协议,如http协议

相同的地址

相同的端口号

如上三个相同即为同源请求会成功。但是如果三个条件有一个不满足,那么就是跨域请求。在跨域请求时,浏览器认为此次请求是不安全的,所以请求会失败。

但是在实际生活中,跨域请求随处可见,那么我们就应该去解决这个跨越请求的需求。

解决:我们一般使有两种解决方案

CORS,主流解决方案。

JSONP,只支持GET请求。

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

1.安装中间件:npm i cors

2.导入中间件:const cors = require('cors');

3.注册中间件:server.use(cors())

ps:通过cors中间件就能简单的解决请求跨域问题

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

车厢调度(train)(栈)

目录 题目描述 解题思路: 代码部分: 题目描述 有一个火车站,铁路如图所示,每辆火车从A驶入,再从B方向驶出,同时它的车厢可以重新组合。假设从A方向驶来的火车有n节(n≤1000)&…

Revit中关于屋顶编辑线移动的问题

一、Revit中关于屋顶编辑线移动的问题 在绘制屋顶的时候,如果出现有稍微偏差的时候,个别习惯移动编辑线,这种方法是不可取的,接下来为大家介绍一下这种方法的问题所在。 首先我们绘制几面这样的墙体,主要做测试用的&am…

锁升级之Synchronized

Synchronized JVM系统锁一个对象里如果有多个synchronized方法,同一时刻,只要有一个线程去调用其中的一个synchronized方法,其他线程只能等待!锁的是当前对象,对象被锁定后,其他线程都不能访问当前对象的其…

流程引擎之发展史及对比总结

流程引擎渊源市场上比较有名的开源流程引擎有 jBPM、Activiti、Camunda、Flowable 和 Compileflow。其中 jBPM、Activiti、Flowable、camunda 四个框架同宗同源,祖先都是 jbpm4,开发者只要用过其中一个框架,基本上就会用其它三个。而 Compile…

SOFA Weekly|SOFANew、本周贡献 issue 精选

SOFA WEEKLY | 每周精选 筛选每周精华问答,同步开源进展欢迎留言互动~SOFAStack(Scalable Open Financial Architecture Stack)是蚂蚁集团自主研发的金融级云原生架构,包含了构建金融级云原生架构所需的各个组件&#…

基于Gromacs配体修饰自由能FPE计算(手动版)

基于Gromacs配体修饰自由能FPE计算(手动版) 本教程来自于https://github.com/huichenggong/Learning-Computation-with-Chenggong/tree/main/CC_news_008_ddG_uniFEP 我们将要使用的系统来自这篇论文 配体和受体pdb文件 A. 介绍 在本教程中,我们将使用非平衡自…

使用开源实时监控系统 HertzBeat 5分钟搞定 Mysql 数据库监控告警

使用开源实时监控系统 HertzBeat 对 Mysql 数据库监控告警实践,5分钟搞定! Mysql 数据库介绍 MySQL是一个开源关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的开源关系型数据库管理系统之…

VHDL语言基础-时序逻辑电路-锁存器

目录 锁存器的设计: RS锁存器: 真值表: 电路结构图: RS锁存器的仿真波形如下: D锁存器: D锁存器的仿真波形如下: 锁存器的设计: 为了与触发器相类比,我们先介绍锁…

奇舞周刊第 481 期 数据不够实时:试试长连接?

记得点击文章末尾的“ 阅读原文 ”查看哟~下面先一起看下本期周刊 摘要 吧~奇舞推荐■ ■ ■数据不够实时:试试长连接?在特定场景下,我们往往需要实时的去获取最新的数据,如获取消息推送或公告、股票大盘、聊天消息、实时的日志和…

面试(九)小米C++开发一面 21.11.02

1、局部变量与全局变量的区别?可以同名嘛? 首先是作用域: 局部变量只在变量声明的代码块范围内生效 全局变量在其声明后的所有位置都能访问到 在局部变量与全局变量同名的情况下,全局变量会被屏蔽掉,只会使用局部变量的内容 2、extern 当在a.c中想要使用b.c中的函数fu…

【Mac OS】JDK 多版本切换配置

前言 由于不同的项目可能需要使用的 JDK 版本不一样,所以在系统中配置多个 JDK 版本,并且能随时切换,是一个必要的配置。 查看已安装的 JDK 版本 /usr/libexec/java_home -V框框1是执行的命令 框框2是当前系统下所有的 JDK 版本 框框3是当…

1.7 Web学生管理系统

1.定义通讯协议基于前面介绍过的 FLask Web 网站 与 urlib 的访问网站的方法,设计一个综合应用实例。它是一个基于 Web 的学生记录管理程序。学生的记录包括 id(学号) 、name(姓名) 、grade(成绩),服务器的作用是建立与维护一个Sqllite 的学生数据库 stu…

单目相机、双目相机和RGB-D相机学习笔记(一些视频和博文网址)

目录1. 单目相机1.1 摄像头原理1.2 单目相机的标定2 双目相机2.1 双目相机定位原理2.2 双目相机的缺陷3 RGB-D相机3.1 深度相机结构光原理3.2 RGB-D相机的应用1. 单目相机 1.1 摄像头原理 视频网址:【全网最详细】摄像头原理分析(约25分钟课程&#xf…

RPC框架设计的安全性考量

RPC里面该如何提升单机资源的利用率,你要记住的关键点就一个,那就是“异步化”。调用方利用异步化机制实现并行调用多个服务,以缩短整个调用时间;而服务提供方则可以利用异步化把业务逻辑放到自定义线程池里面去执行,以…

springboot 注解

上一篇:初识springboot接收参数常用注解RequestBody 常用于POST表单提交参数接收RequestMapping("/test") public String test(RequestBody String data){return data; }PathVariable 获取路径上的参数:/test/{id} RequestMapping("/test…

开源流程引擎Camunda

开源流程引擎Camunda 文章作者:智星 1.简介 Camunda是一个轻量级的商业流程开源平台,是一种基于Java的框架,持久层采用Mybatis,可以内嵌集成到Java应用、SpringBooot应用中,也可以独立运行,其支持BPMN&a…

ThingsBoard-规则引擎介绍

1、什么是规则引擎? 规则引擎是一个易于使用的框架,用于构建基于事件的工作流。有3个主要组成部分: 消息- 任何传入事件。它可以是来自设备的传入数据、设备生命周期事件、REST API 事件、RPC 请求等。规则节点- 对传入消息执行的功能。有许多不同的节点类型可以过滤、转换…

微信 API 中调用客服消息接口提示错误返回限制

错误的信息如下:errcode45015, errmsgresponse out of time limit or subscription is canceled rid: 5f8fd8b7-0f8aa1a9-4b6215a5微信的文档看着这微信不清不楚的文档:微信公众平台在这个文档界面中,有句话:这句话,我…

【信息学CSP-J近16年历年真题64题】真题练习与解析 第13题之标题统计

标题统计 描述 凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符? 注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字符数时,空格和换行符不计算在内。 输入 输入文件只有一行,一个字符串 s。 输出 输出文件只有一行,包含一个整…

原型、原型链、__proto__与prototype的区别、继承

一.什么是原型与原型链 根据MDN官方解释: JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象[[Prototype]] ,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类…