失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > node.js学习总结:node.js的内置模块 模块化 npm与包 express 前后端身份认证 JWT认证机制

node.js学习总结:node.js的内置模块 模块化 npm与包 express 前后端身份认证 JWT认证机制

时间:2021-03-16 03:45:10

相关推荐

node.js学习总结:node.js的内置模块 模块化 npm与包 express 前后端身份认证 JWT认证机制

node.js学习总结

什么是node.jsnode.js的内置模块fs系统模块path路径模块http模块模块化npm与包expressexpress路由express+mysql前后端身份认证JWT认证机制

什么是node.js

node.js是基于Chrome V8引擎的javaScrit运行环境node.js中的javaScript运行环境注意:1.浏览器是javaScript的前端运行环境2.Node.js是javaScript的后端运行环境3.node.js中无法调取DOM和BOM等浏览器内置APInode.js可以做什么?1.基于express框架,可以快速构建Web应用2.基于Electron框架,可以构建跨平台的桌面应用3.基于restify框架,可以快速构建API接口项目4.读写和操作数据库,创建实用的命令行工具辅助前端开发,etcnodejs的学习路径:javaScript基础语法+node.js内置模块(fs,path,http等)+第三方API模块(express,mysql等)

node.js的内置模块

fs系统模块

fs是node.js官方提供的,用来操作文件的模块。它提供了一系列的方法和属性用来满足用户对文件的操作需求1.fs.readFile()方法,用来读取指定文件的内容2.fs.writeFile()方法,用来向指定的文件中写入内容在js代码中使用fs模块(nodejs内置函数)1.导入const fs = require('fs')1.读取指定文件内容使用fs.readFile()读取指定文件的内容:语法:fs.readFile(path,option,callback)参数解读:1.path 必选参数,字符串,表示文件的路径2.option 可选参数,表示使用什么编码格式来读取文件3.callback 必选参数,文件读取后,通过回调函数拿到读取结果示例:const fs = require('fs') //导入fs模块fs.readFile('./a.txt', 'utf8',function(err,dataStr){console.log(err)console.log(dataStr)})2.向指定模块中写入内容fs.writeFile()的语法格式使用fs.writeFile()方法写入1.fs.writeFile(path,data,option,function)参数解读:参数1:path 必选参数,文件的路径参数2:data 必选参数,表示要写入的内容参数3:编码格式参数4:回调函数 必选参数实例:const fs = require('fs')fs.writeFile('./file/a.txt',"hello",function(err){console.log(err)})*注意:1.fs.writeFile() 方法只能用来创建文件,不能用来创建路径2.重复调用fs.writeFile()写入同一个文件,新写入的文件内容会覆盖之前的旧内容3.fs模块–路径动态拼接的问题在使用fs 模块操作文件时,如果提供的操作路径是以/或../开头的相对路径时,很容易出现路径动态拼接错误的问题。原因:代码在运行的时候,会以执行node 命令时所处的目录,动态拼接出被操作文件的完整路径。解决这个问题:1.提供一个完整的文件路径2.不使用./ ../ 使用_dirname 表示当前文件所在的目录//解决文件路径拼接问题const fs = require('fs')// __dirname 表示当前文件所处的目录console.log(__dirname);fs.readFile(__dirname+"/file/a.txt",'utf8',function(err, data) {if (err){return console.error(err)} console.log(data)})

path路径模块

path模块是Node.js官方提供的,用来处理路径的模块,它提供了一系列的方法和属性,用来满足用户对路径的处理和需求例如:path.join()方法,用来将路径片段拼接成一个完整的路径字符串path.basename()方法,用来从路径中将文件名解析出来在js代码中使用fs模块(nodejs内置函数)1.导入const path = require('path') 路径拼接path.join()path.join()方法。可以将多个路径片段拼接为完整的路径字符串const pathStr = path.join('/a','/b/c','../','./d','e')console.log(pathStr) // ../会抵消前面的一个路径 \a\b\d\econst pathStr1 = path.join(__dirname,'/file/1.txt')console.log(pathStr1) // 输出 当前文件所在目录 \file\1.txt*涉及到路径一般使用path.join()进行路径的拼接path.basename()的语法格式使用path.basename()方法,可以获取路径中的最后一部分,经常通过这个方法获取路径中的文件名path.basename(pth,ext)path<String> 必选参数,表示一个路径的字符串ext<String> 可选参数,表示文件的扩展名返回<String> 表示路径中最后的一部分获取路径中的扩展名使用path.extname()方法,可以获取路径中扩展名部分,语法格式如下path.extname(path)path<String> 必选参数,表示一个路径的字符串返回<String> 返回得到的扩展名字符串

http模块

1.什么是http模块http模块是Node.js 官方提供的、用来创建web服务器的模块。通过 http模块提供的 http=createServer()方法就能方便的把一台普通的电脑,变成一台Web 服务器,从而对外提供 Web资源服务。2.如何使用http模块 1.首先导入 const http = require('http');3.http模块的作用在Node,js中,我们不需要使用lIS、Apache等这些第三方web服务器软件。因为我们可以基于Node.js 提供的http模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供web服务。服务器相关的概念1.IP地址Ip地址就是互联网上每台计算机的唯一地址,因此IP地址具有唯一性。如果把"个人电脑"比作"一台电话",那么"IP地址"就相当于"电话号码"只有在知道对方IP地址的前提下,才能与对应的电脑之间进行数据通信。2.域名和域名服务器尽管IРP地址能够唯一地标记网络上的计算机,但IP地址是一长串数字,不直观,而且不便于记忆,于是人们又发明了另一套字符型的地址方案,即所谓的域名(Domain Name)地址IP地址和域名是一—对应的关系,这份对应关系存放在一种叫做域名服务器(DNS,Domain name server)的电脑中。使用者只需通过好记的域名访问对应的服务器即可,对应的转换工作由域名服务器实现。因此,域名服务器就是提供IР地址和域名之间的转换服务的服务器。3.端口号计算机中的端口号,就好像是现实生活中的门牌号一样。通过门牌号,外卖小哥可以在整栋大楼众多的房间中,准确把外卖送到你的手中。同样的道理,在一台电脑中,可以运行成百上千个web服务。每个web服务都对应一个唯一的端口号。客户端发送过来的网络请求,通过端口号,可以被准确地交给对应的web 服务进行处理。每个端口号只能被一个web服务使用创建最基本的web服务器1.创建web服务的基本步骤1.导入http模块const http = require('http');2.创建web服务实例 通过http.creatServer()方法快速创建web服务实例const server = http.createServer();3.为服务器实例绑定request事件,建通客户端的请求// 使用服务器实例 .on()方法,为服务器绑定一个request事件server.on('request',(req,res)=>{// 只要客户端来请求我们自己的服务器 就会触发 request事件 从而调用这个事件处理函数console.log("Someone visit our web server")})4.启动服务调用服务器实例的.listen()方法,即可启动当前的web服务实例://调用server。listen(端口号,cb回调方法) 即可启动web服务器server.listen(80,()=>{console.log('请访问 http://127.0.0.1:80')})2.req请求对象只要服务器接收到客户端的请i去,就会调用server.on()为服务器绑定的request事件处理函数如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下方式:server.on('request',(req, res) => {// req.url 是客户端请求的url地址const url = req.url;// req.method 是客户端请求的method类型const method = req.method;const str = `你请求的url:${url},请求方式是:${method}`;console.log(str);})3.res响应对象在服务器的request事件处理函数中,如果想访问服务器相关的数据或属性,可以使用如下的方式server.on('request',(req, res) => {// req.url 是客户端请求的url地址const url = req.url;// req.method 是客户端请求的method类型const method = req.method;const str = `你请求的url:${url},请求方式是:${method}`;//为了防止中文显示乱码的问题,需要设置响应头Content-Type的值为 text/html; charset=utf-8res.setHeader( 'Content-Type' ,'text/html; charset=utf-8 ')//调用res.send向客户端响应一些内容res.end(str)})*如果不设置相应头 res.end()返回中文会乱码设置响应头:res.setHeader( 'Content-Type' ,'text/html; charset=utf-8 ')根据不同的url地址响应不同的html内容核心步骤:1.获取请求的url地址2.设置默认的响应内容 404 NOT Fount3.判断用户请的是否为/或/index.html 首页4.判断用户请求的是否为/about.html 页面5.设置content-Type响应头,防止中文乱码6.使用res.end把内容响应给客户端

模块化

编程领域中的模块化,就是遵守固定的规则,把一个大的文件查分成独立并且相互依赖的多个小模块把代码进行模块化才分的好处:1.提高代码的复用性2.提高代码的可维护性3.可以实现按需加载模块化规范模块化规范就是对模块化进行才分组合时需要遵守的规则使用什么样的语法格式来引用模块?在模块中使用什么样的语法格式向外暴露成员模块化规范的好处:大家遵守同样的模块化规范写代码,降低了沟通的成本,极大的方便了各模块之间的相互调用。1.node.js中模块的分类node.js根据模块的来源不同 ,将模块计划分为3大类,分别是:1.内置模块(内置模块由nodejs官方提供的,例如:fs,path,http等)2.自定义模块(用户创建的.js文件,都是自定义模块)3.第三方模块(由第三方开发出来的模块,使用前需要下载)2.加载模块使用require()方法,可以加载内置模块,用户自定义模块,第三方模块进行使用//1.加载内置模块const fs = require('fs');//2.加载自定义模块const custom = require('./custom.js');//3.加载第三方模块const moment = require('moment');*注意:使用require方法加载其他模块时候,会执行被加载模块中的代码在加载require加载用户模块期间,可以省略后缀名3.node.js中模块作用域什么式模块作用域和作用域函数类似,在自定义模块中定义的变量,方法等成员,只能在当前模块内被访问,这种模块级别的访问限制叫做模块作用域模块作用域的好处:防止全局变量污染问题4.向外共享模块作用域中的成员1.module对象在每个.js自定义模块中都有一个module对象,他里面存储了和当前模块有关的信息打印moduleModule {id: '.',path: 'E:\\student\\NODEJS\\04.模块化',exports: {},parent: null,filename: 'E:\\student\\NODEJS\\04.模块化\\05.演示module对象.js',loaded: false,children: [],paths: ['E:\\student\\NODEJS\\04.模块化\\node_modules','E:\\student\\NODEJS\\node_modules','E:\\student\\node_modules','E:\\node_modules']}2.module.exports对象 默认为空对象在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用外界用require()方法导入自定义模块时,得到的就是module.exports所指的对象3.共享成员的注意点使用require()方法导入模块时,导入的结果 永远以module.exports指向的对象为准4.exports对象由于module.expres写起来比较复杂,为了简化代码,提供了exports对象。默认情况下exports和module.exports指向同一个对象,最终结果还是以module.exports指向的为准*注意:为了防止混乱,建议不要再同一个模块中同时使用exports和module.expres5.node.js中的模块化规范node.js遵循了conmmonJS模块化规范,commonJS规定了模块的特性和各模块之间如何相互依赖commonJS1.每个模块内部,module变量代表当前模块2.module变量是一个对象,它的exports属性(即module.exports)是对外接口3.加载模块时候,其实加载该模块的module.exports属性。require()方法用于加载模块

npm与包

1.什么是包?nodejs中的第三方模块又叫做包2.包的来源不同于node.js中内置模块和自定义模块,包是由第三方个人或团队开发出来的,免费供所有人使用注意:Node.js中的包都是免费且开源的,不需要付费即可免费下载使用3.为什么需要包?由于node.js的内置模块仅仅提供了一些底层API,导致在基于模块进行项目开发时候,效率很低包是基于内置模块封装出来的,提供了高级,更方便的API,极大的提高了开发效率4.从哪里下载包从/ 网站搜索自己所需要的包5.如何下载包npm 包管理器 安装node的时候自动安装了6.在项目中装包的命令npm install 包的完整名称简写 npm i 包的完整名称7.初次装包,文件里面多了哪些文件?初次装包完成后,在项目文件夹下多了一个叫做 node_modules的文件夹和package-lock.json的配置文件node modules文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包。package-lockjson配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等。*注意:程序员不要手动修改node modules或package-lockjson文件中的任何代码,npm包管理工具会自动维护它们。8.安装指定版本的包默认情况下,使用npm install命令安装包的时候,会自动安装最新版本的包。如果需要安装指定版本的包,可以在包名之后,通过@符号指定具体的版本,例如:npm i moment@2.22.29.包的语义化版本规范包的版本号是以“点分十进制”形式进行定义的,总共有三位数字,例如2.24.0其中每一位数字所代表的的含义如下:第1位数字:大版本第2位数字:功能版本第3位数字:Bug修复版本版本号提升的规则:只要前面的版本号增长了,则后面的版本号归零。10.3.快速创建package.jsonnpm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理配置文件://作用:在执行命令所处的目录中,快速新建package.json文件npm init -y注意:上述命令只能在英文的目录下成功运行!所以,项目文件夹的名称一定要使用英文命名.不要使用中文,不能出现空格。运行npm install 命令安装包的时候,npm包管理工具会自动把包的名称和版本号,记录到package.json中。11.一次性安装所有的包可以运行npm install命令(或npm i)一次性安装所有的依赖包:1//执行npm install命令时,npm包管理工具会先读取package.json 中的 dependencies 节点2//读取到记录的所有依赖包名称和版本号之后,npm包管理工具会把这些包一次性下载到项目中3 npm install12.卸载包npm uninstall 包名13.devDependencies节点如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDependencies节点中。与之对应的,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到dependencies 节点中。您可以使用如下的命令,将包记录到devDependencies节点中:1//安装指定的包,并记录到devDependencies节点中2 npm i 包名-D3//注意:上述命令是简写形式,等价于下面完整的写法:4 npm install 包名 --save-dev14.解决下包速度慢的问题1.为什么下包速度慢在使用npm下包的时候,默认从国外的/服务器进行下载,此时,网络数据的传输需要经过漫长的海底光缆,因此下包速度会很慢。2.切换npm的下包镜像源下包的镜像源,指的就是下包的服务器地址。1#查看当前的下包镜像源2 npm config get registry3# 将下包的镜像源切换为淘宝镜像源4 npm config set registry=https://registry./5 #检查镜像源是否下载成功6 npm config get registry3.nrm为了更方便的切换下包的镜像源,我们可以安装nrm这个小工具,利用nrm 提供的终端命令,可以快速查看和切换下包的镜像源。1 #通过npm包管理器,将 nrm安装为全局可用的工具2 npm i nrm -g3#查看所有可用的镜像源4 nrm ls5#将下包的镜像源切换为taobao镜像6 nrm use taobao

express

Express简介1.什么是Express官方给出的概念:Express是基于Node.js 平台,快速、开放、极简的Web开发框架。通俗的理解:Express的作用和Node.js内置的http模块类似,是专门用来创建Web服务器的。Express的本质:就是一个npm上的第三方包,提供了快速创建Web服务器的便捷方法。Express的中文官网: /Express 能做什么对于前端程序员来说,最常见的两种服务器,分别是:Web 网站服务器:专门对外提供Web 网页资源的服务器。API接口服务器:专门对外提供API接口的服务器。使用Express,我们可以方便、快速的创建Web 网站的服务器或 API接口的服务器。1.安装在项目所处的目录中,运行如下的终端命令,即可将express安装到项目中使用:1 npm i express@4.17.12.创建基本的Web服务器1 // 1.导入express2 const express = require( ' express ' )3 // 2.创建web服务器4 const app = express()6 // 3.调用app.listen(端口号,启动成功后的回调函数),启动服务器7 app.listen(80,() =>{console.log( ' express server running at http: //127.0.0.1')})3.监听get请求通过app.get( )方法,可以监听客户端的GET请求,语法如下:1.参数1∶客户端请求的URL 地址2.参数2:请求对应的处理函数3.req:请求对象((包含了与请求相关的属性与方法)4.res:响应对象(包含了与响应相关的属性与方法)5 app.get('请求URL',function(req,res) {/*处理函数*/ })4.监听post请求通过app.post( )方法,可以监听客户端的GET请求,语法如下:1.参数1∶客户端请求的URL 地址2.参数2:请求对应的处理函数3.req:请求对象((包含了与请求相关的属性与方法)4.res:响应对象(包含了与响应相关的属性与方法)5 app.post('请求URL',function(req,res) {/*处理函数*/ })5.把内容响应给客户端通过res.send)方法,可以把处理好的内容,发送给客户端:app.get( ' /user ' , (req, res) =>{向客户端发送JSON 对象res.send({ name: 'zs ',age: 20,gender: '男'})})app.post( " /user'. (req,res) =>{向客户端发送文本内容res.send( '请求成功')})6.获取URL中携带的查询参数通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数:app.get( '/', (req,res) => {//req.query 默认是一个空对象//客户端使用?name=zs&age=20这种查询字符串形式,发送到服务器的参数,//可以通过req.query对象访问到,例如:// req.query.name req.query.ageconsole.log(req. query)7.获取URL中的动态参数通过req.params对象,可以访问到URL中,通过:匹配到的动态参数://URL地址中,可以通过:参数名的形式,匹配动态参数值app.get( '/user/:id',(req,res) => {//req.params 默认是一个空对象//里面存放着通过:动态匹配到的参数值console.log(req. params)})8.托管静态资源1.express.static()express提供了一个非常好用的函数,叫做express.static(),通过它,我们可以非常方便地创建一个静态资源服务器,例如,通过如下代码就可以将public目录下的图片、CSS文件JavaScript 文件对外开放访问了:app.use(express.static('public'))*如过不生效const path = require('path');app.use(express.static(path.join(__dirname, 'public')))挂载路径前缀如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下的方式:app.use( '/public' , express.static( 'public' ))现在,你就可以通过带有/public 前缀地址来访问public目录中的文件了:

express路由

1.Express中的路由在Express 中,路由指的是客户端的请求与服务器处理函数之间的映射关系。Express 中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数,格式刻app.METHOD(PATH,HANDLER)2.Express中的路由的例子匹配GET请求,且请求URL为/app.get( '/',function (req,res) {res.send( 'Hello world! ')})匹配POST请求,且请求URL为/app.post('/', function (req,res) {res.send( ' Got a PoST request ')})3.路由的匹配过程1. 每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数。2. 在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的URL同时匹配成功,则 Express 会将这次请求,转交给对应的function 函数进行处理。3. 路由匹配的注意点:按照定义的先后顺序进行匹配请求类型和请求的URL同时匹配成功,才会调用对应的处理函数 4.路由的使用 在Express 中使用路由最简单的方式,就是把路由挂载到app 上,示例代码如下:const express = require('express')const app = express()//挂载路由app.get('/',(req, res) =>{res.send("hello word")})app.post('/',(req, res) =>{res.send("post request")})app.listen(3000,() => {console.log('http://localhost:3000');})5.模块化路由为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。将路由抽离为单独模块的步骤如下:创建路由模块对应的.js文件1.创建路由模块对应的.js文件2.调用express.Router()函数创建路由对象3.向路由对象上挂载具体的路由4.使用module.exports向外共享路由对象//这是路由模块// 1.导入expressconst express = require('express')//2.创建路由对象const router = express.Router()//3. 挂载具体的路由router.get('/user/list',(req, res) => {res.send("get user list")})router.post('/user/add',(req, res) => {res.send('post user add')})//4.向外导出路由module.exports = router5.使用app.use()函数注册路由模块const express = require('express');const app = express();//1.导入路由模块const routes = require('./05.router');//2.注册路由模块 app.use这个函数的作用,就是用来注册全局的中间件app.use(routes)app.listen(3000,()=>{console.log('listening on 3000')});给路由添加统一的访问前缀app.use('/api',routes)6.EXpress中间件1.什么是中间件中间件:特指业务流程的中间处理环节2.express中间件的调度流程当请求到达Express的服务之后,可以连续调用多个中间件,从而对这次请求进行预处理3.Express中间件的格式Express的中间件,本质上就是一个function处理函数,Express中间件的格式如下:app.get( '/',(req,res,next) => {next()})app.listen(3000);*注意:中间件函数的形参列表中,必须包含next参数,而路由器处理函数只包含req和res4.next()形参的作用next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由7.Express中间件初体验1.定义中间件可以通过如下方式定义,定义一个最简单的中间件//常量 mw所指向的,就是一个中间件函数const mw = function(req,res,next){console.log("这是一个最简单的中间件")// 注意:在当前中间件的业务处理完毕后,必须调用next()函数// 表示把流转关系交给下一个中间件或路由next()}2.全局生效的中间件客户端发起任何请求,到达服务器之后,都会触发的中间件叫做全局生效中间件通过调用app.use()中间件函数,即可定义一个全局中间件,示例代码如下:const express = require('express')const app = express()const port = 3000// 定义一个最简单的中间件函数const mw = function (req, res,next) {console.log("这是最简单的中间件函数");//把流转关系,转交给下一个中间件next()}// 将mw注册成为全局的中间件app.use(mw)app.get('/', (req, res) =>{console.log("调用了/这个路由");res.send('Hello World!')})app.get('/user', (req, res) => {console.log(`调用了${req.url}`);res.send('my is user')})app.listen(port, () => console.log(`Example app listening on port ${port}!`))3.定义全局中间件的简化形式app.use((req, res, next) => {console.log("这是简化的全局中间件");next();})4.中间件的作用多个中间件之间 共享一份req和res基于这个特性,我们可以在上有的中间件中,统一为req或res对象添加自定义的属性和方法,供下游的中间件或路由使用5.定义多个全局中间件可以使用app.use()连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件的先后顺序,依次进行调用,实例代码:// 定义第一个全局中间件app.use((req, res, next) =>{console.log("调用了第一个全局中间件");next()})//定义第二个全局中间件app.use((req, res, next) =>{console.log("调用了第二个全局中间件");next()})//定义一个路由app.get('/', (req, res, next) =>{res.send(req.url)})6.局部生效的中间件不使用app.use()定义的中间件,叫做局部生效的中间件 示例代码如下const mw = (req, res, next) => {console.log("调用局部生效中间件");next()}app.get('/',mw, (req, res) => {res.send("/")})app.get('/user',(req, res) => {res.send("/user")})7.定义多个局部中间件可以在路由中通过如下两种等价的方式,使用多个局部中间件//创建局部生效的中间件const mw1 = (req, res, next) =>{console.log('调用了第一个局部生效的中间件');next()}const mw2 = (req, res, next) =>{console.log("调用了第二个局部生效的中间件");next()}// 以下两种写法均为完全等价,可以使用任意一种app.get('/', mw1,mw2,(req, res) =>{res.send('/')})app.get('/user',[mw1,mw2],(req, res) =>{res.send('/user')})8.了解中间件的5个注意事项1.一定要在路由注册之前注册中间件2.客户端发送过来的请求,可以连续调用多个中间件进行处理3.执行完中间件的业务代码之后,不要忘记调用next()函数4.为了防止逻辑混乱,盗用next()函数后不要频再写额外的代码5.连续调用中间键的时候多个中间件之间,共享req和res对象8.中间件的分类1.应用级别的中间件 app通过app.use()或app.get()或app.post()绑定到app实例上的中间件,叫做应用级别的中间件2.路由级别的中间件 router绑定到express.Routerl)实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到 app实例上,路由级别中间件绑定到router实例上 3.错误级别的中间件错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。格式:错误级别中间件的function处理函数中,必须有4个形参,形参顺序从前到后,分别是(err, req, res, next)。app.get( ' /', function (req,res) { // 路由//抛出一个自定义的错误throw new Error( '服务器内部发生了错误!')res.send( 'Home Page.')})app.use( function (err,req,res,next) { //错误级别的中间件console.log( '发生了错误:' +err.message)// 在服务器打印错误消息res.send( 'Error! ' +err.message) // 2.2向客户端响应错误相关的内容})** 错误级别中间件,必须注册再所有路由之后4.Express内置的中间件自Express 4.16.0版本开始,Express 内置了3个常用的中间件,极大的提高了Express 项目的开发效率和体验1.express.static快速托管静态资源的内置中间件,例如:HTML文件、图片、CSS样式等(无兼容性)2.express.json解析JSON格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)3.express.urlencoded解析URL-encoded格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)//配置解析application/json格式数据的内置中间件app.use(express.json())//配置解析 application/x-ww-form-urlencoded格式数据的内置中间件app.use(express.urlencoded( { extended: false }))app.use(express.json())app.use(express.urlencoded({extended:false}))app.post('/book', function (req, res) {//在客户端可以使用req.body这个属性,来接收客户端发送过来的请求数据// 默认情况下,如果不配置解析表单的中间件,则req.body 默认等于 undefinedconsole.log(req.body);res.send('POST request to the homepage')})app.get('/', (req, res) => {res.send('GET request to the homepage')})app.post('/', function (req, res) {// 在服务器端,可以通过req.body 来获取JSON格式和url-encoded格式的数据console.log(req.body);res.send('POST request to the homepage')})5.第三方的中间件非Express 官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。例如:在express@4.16.0之前的版本中,经常使用body-parser这个第三方中间件,来解析请求体数据。使用步骤如下:运行npm install body-parser安装中间件使用require 导入中间件6.解决跨越问题中间件corscors 是 Express的一个第三方中间件。通过安装和配置cors 中间件,可以很方便地解决跨域问题。1.运行 npm install cors 安装中间件2.使用const cors = require('cors') 导入中间件3.在路由之前调用app.use(cors) 配置中间件什么是corsCORS (Cross-Origin Resource Sharing,跨域资源共享)由一系列HTTP响应头组成,这些HTTP响应头决定浏览器是否阻止前端JS代码跨域获取资源。浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了CORS相关的HTTP响应头,就可以解除浏览器端的跨域访问限制。CORS 的注意事项CORS主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了CORS的接口。CORS在浏览器中有兼容性。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了CORS的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。CORS 响应头部-Access-Control-Allow-Origin响应头部中可以携带一个 Access-Control-Allow-Origin字段,其语法如下:Access-Control-Allow-origin: <origin>|*其中,origin 参数的值指定了允许访问该资源的外域URL。例如,下面的字段值将只允许来自的请求:res.setHeader ( 'Access-Control-Allow-Origin', 'http:/')如果指定了Access-Control-Allow-Origin字段的值为通配符*,表示允许来自任何域的请求,示例代码如下:res.setHeader( 'Access-Control-Allow-Origin', '*')CORS 响应头部 Access-Control-Allow-Headers默认情况下,CORS仅支持客户端向服务器发送如下的9个请求头:Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width ,Content-Type (值仅限于text/plain、multipart/form-data、application/x-www-form-urlencoded三者之一)如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败!允许客户端额外向服务器发送Content-Type请求头和X-Custom-Header 请求头注意:多个请求头之间使用英文的逗号进行分割res.setHeader(' Access-Control-Allow-Headers','Content-Type,X-Custom-Header ' )CORS响应头部– Access-Control-Allow-Methods默认情况下,CORS仅支持客户端发起GET、POST、HEAD请求。如果客户端希望通过PUT、DELETE等方式请求服务器的资源,则需要在服务器端,通过Access-Control-Alow-Methods来指明实际请求所允许使用的HTTP方法。只允许POST、GET、DELETE、HEAD请求方法res.setHeader( 'Access-Control-Allow-Methods ','POST,GET,DELETE,HEAD')允许所有的 HTTP请求方法res.setHeader( ' Access-Control-Allow-Methods ', '*')简单请求:同时满足一下两个大条件的请求,就属于简单请求1.请求方式GET,POST,HEAD 三者之一2.HTTP头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language,Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type (只有三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)预检请求只要符合以下任何一个条件的请求,都需要进行预检请求:1.请求方式为GET、POST、HEAD之外的请求Method类型2.请求头中包含自定义头部字段3.向服务器发送了application/json格式的数据在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这-次的OPTION请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。简单请求和预检请求的区别简单请求的特点:客户端与服务器之间只会发生一次请求。预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求。

express+mysql

安装mysql模块npm install mysql配置mysql模块// 1.导入mysql模块const mysql = require( ' mysql' )//2.建立与 MySQL数据库的连接const db = mysql.createPool({host: '127.0.0.1', //数据库的IP地址user : 'root',//登录数据库的账号password: 'admin123',//登录数据库的密码database: 'my_db_01' //指定要操作哪个数据库})测试mysql模块是否正常工作// 测试mysql 是否正常工作db.query('SELECT 1', (err, result) => {if (err) {return console.log("错误");}//只要能打印出{'1':1}的结果,就证明数据库连接成功console.log(result);})查询数据// 查询list表中的所有数据const sql = "SELECT * FROM list";db.query(sql, (err, result) => {// 查询失败if (err) { return console.log("查询数据失败"+err.message); }// 查询失败 得到一个数组console.log(result);})插入数据// 向user表中插入一条数据const user = {username:'root',password:'123456'}const userSql = 'INSERT INTO user (username,password) VALUES (?, ?)'db.query(userSql,[user.username,user.password],(err, result)=>{// 插入失败if (err) { return console.log(err.message); }// 插入成功if (result.affectedRows === 1){ console.log("插入成功")}})简便的方式:const user = {username:'root',password:'123456'}const userSql = 'INSERT INTO user set ?'db.query(userSql,user,(err, result)=>{// 插入失败if (err) { return console.log(err.message); }// 插入成功if (result.affectedRows === 1){ console.log("插入成功")}})更新数据// 1.要更新的数据对象const user = {id:1,username:'lisi',password:'789456'}const upSql = 'UPDATE user SET username=?,password = ? WHERE id=?'db.query(upSql,[user.username,user.password,user.id],(err, result)=>{if (err) { return console.log(err.message); }if (result.affectedRows === 1){ console.log("更新数据成功")}})删除数据:// 删除user表中的一条数据const sql = 'DELETE FROM user WHERE id= ?'db .query(sql,[1], (err, result)=>{if (err){return console.log(err.message);}if (result.affectedRows === 1){ console.log("删除成功")}})标记删除使用DELETE语句,会把真正的把数据从表中删除掉。为了保险起见,推荐使用标记删除的形式,来模拟删除的动作。所谓的标记删除,就是在表中设置类似于status这样的状态字段,来标记当前这条数据是否被删除。当用户执行了删除的动作时,我们并没有执行DELETE语句把数据删除掉,而是执行了UPDATE语句,将这条数据对应的status字段标记为删除即可。

前后端身份认证

web开发模式目前主流的Web开发模式有两种,分别是:1基于服务端渲染的传统 Web开发模式2基于前后端分离的新型Web开发模式1.服务端渲染的Web开发模式服务端渲染的概念:服务器发送给客户端的HTML页面,是在服务器通过字符串的拼接,动态生成的。因此,客户端不需要使用Ajax这样的技术额外请求页面的数据.2.服务端渲染的优缺点优点:前端耗时少。因为服务器端负责动态生成HTML内容,浏览器只需要直接渲染页面即可。尤其是移动端,更省电。有利于SEO。因为服务器端响应的是完整的HTML页面内容,所以爬虫更容易爬取获得信息,更有利于SEO。缺点:占用服务器端资源。即服务器端完成HTML页面内容的拼接,如果请求较多,会对服务器造成一定的访问压力。不利于前后端分离,开发效率低。使用服务器端渲染,则无法进行分工合作,尤其对于前端复杂度高的项目,不利于项目高效开发。3.前后端分离的 Web开发模式前后端分离的概念:前后端分离的开发模式,依赖于Ajax技术的广泛应用。简而言之,前后端分离的Web开发模式,就是后端只负责提供API接口,前端使用Ajax调用接口的开发模式。4.前后端分离的优缺点优点:开发体验好。前端专注于UI页面的开发,后端专注于api的开发,且前端有更多的选择性。用户体验好。Ajax技术的广泛应用,极大的提高了用户的体验,可以轻松实现页面的局部刷新。减轻了服务器端的渲染压力。因为页面最终是在每个用户的浏览器中生成的。缺点:不利于 SEO。因为完整的HTML页面需要在客户端动态拼接完成,所以爬虫对无法爬取页面的有效信息。(解决方案:利用Vue、React等前端框架的SSR (server side render)技术能够很好的解决SEO问题! )1.什么是身份认证?身份认证(Authentication)又称“身份验证”、“鉴权”,是指通过一定的手段,完成对用户身份的确认。2.为什么需要身份认证身份认证的目的,是为了确认当前所声称为某种身份的用户,确实是所声称的用户。3.不同开发模式下的身份认证对于服务端渲染和前后端分离这两种开发模式来说,分别有着不同的身份认证方案:1.服务端渲染推荐使用Session 认证机制2.前后端分离推荐使用JWT认证机制Session认证机制1.HTTP协议的无状态性了解HTTP协议的无状态性是进一步学习Session认证机制的必要前提。HTTP协议的无状态性,指的是客户端的每次HTTP请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留每次HTTP请求的状态。2.如何突破HTTP无状态的限制通过Cookie3.什么是CookieCookie是存储在用户浏览器中的一段不超过4KB的字符串。它由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。不同域名下的Cookie 各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的Cookie一同发送到服务器。Cookie的几大特性:1.自动发送2.域名独立3.过期限制4.4KB限制4.Cookie在身份认证中的作用客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的Cookie,客户端会自动将Cookie保存在浏览器中。随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的Cookie,通过请求头的形式发送给服务器,服务器即可验明客户端的身份。 5.Cookie 不具有安全性由于Cookie是存储在浏览器中的,而且浏览器也提供了读写Cookie的API,因此Cookie很容易被伪造,不具有安全性。因此不建议服务器将重要的隐私数据,通过Cookie的形式发送给浏览器。注意:千万不要使用Cookie存储重要且隐私的数据!比如用户的身份信息、密码等。6.提高身份认证的安全性为了防止客户伪造会员卡,收银员在拿到客户出示的会员卡之后,可以在收银机上进行刷卡认证。只有收银机确认存在的会员卡,才能被正常使用。这种“会员卡+刷卡认证”的设计理念,就是Session认证机制的精髓。在express中使用session认证1.安装express-session中间件npm i express-session2.配置session中间件const session = require('express-session')app.use(session({secret: 'xinghuo',resave: false,saveUninitialized: true,}))3.向session中存数据当express-session中间件配置成功后,即可通过 req.session来访问和使用session对象,从而存储用户的关键信息:app.post('/api/login',(req, res) => {if (req.body.username != 'admin' || req.body.password != '123456'){return res.send({statis:1,msg: '登录失败'})}req.session.user = req.body //存储用户信息req.session.idlogin = true //存储登录信息})4.在session中取数据直接在req.session对象上获取之前存储的数据app.post('/', function (req, res) {if(!req.session.islogin){return res.send({status:1,msg: 'fail'})}res.send({status:0,msg: 'success',username : req.session.user.username})})5.清空session调用req.session.destroy()函数,即可清空服务器保存的session 信息6.了解 Session 认证的局限性Session认证机制需要配合Cookie才能实现。由于Cookie 默认不支持跨域访问,所以当涉及到前端跨域请求后端接口的时候,需要做很多额外的配置,才能实现跨域Session认证。 注意:当前端请求后端接口不存在跨域问题的时候,推荐使用Session身份认证机制。当前端需要跨域请求后端接口的时候,不推荐使用Session身份认证机制,推荐使用JWT认证机制。

JWT认证机制

1.JWT的组成部分JWT通常由三部分组成,分别是 Header(头部)、Payload(有效荷载)、Signature(签名)。三者之间使用英文的“.”分隔,格式如下:Header.Payload.Signature2.JWT的三个部分各自代表的含义JWT的三个组成部分,从前到后分别是 Header、Payload、Signature。其中:Payload部分才是真正的用户信息,它是用户信息经过加密之后生成的字符串。Header和Signature是安全性相关的部分,只是为了保证Token的安全性。3.JWT的使用方式客户端收到服务器返回的WT之后,通常会将它储存在localStorage或sessionStorage 中。此后,客户端每次与服务器通信,都要带上这个WT的字符串,从而进行身份认证。推荐的做法是把JWT放在HTTP请求头的Authorization字段中,格式如下:Authorization: Bearer <token>4.expresss中使用JWT1.安装相关的包npm install jsonwebtoken express-jwtjsonwebtoken用于生成JWT字符串express-jwt用于将JWT字符串解析还原成JSON 对象2.导入JWT相关的包使用require()函数,分别导入JWT相关的两个包:// 安装并导入JWT相关的包 分别是 jsionwebtoken 和 express-jwtconst jwt = require('express-jwt')const jsont = require('jsonwebtoken')3.定义secret密钥为了保证JWT字符串的安全性,防止JWT字符串在网络传输过程中被别人破解,我们需要专门定义一个用于加密和解密的secret密钥:当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的WT字符串当把JWT字符串解析还原成JSON对象的时候,需要使用secret密钥进行解密4.在登录成功后生成JWT字符串调用jsonwebtoken包提供sign()方法,将用户的信息加密成JWT字符串,响应给客户端// 定义一个secret密钥,建议将密钥命名为 secretKeyconst secretKey = 'itbnsadklsdbabsdalhnlk ^_^'//登录接口app.post('/api/login', function (req, res) {//将req.body 请求体中的数据,转存为userinfo常量const userinfo = req.body// 登录失败if(userinfo.username != 'admin' || userinfo.password != '123456')return res.send({status:400,message:'登录失败'})// 登录成功// 在登录成功之后调用 jwt.sign()方法生成jwt字符串。并通过token属性发送给客户端const token = jsont.sign({username: userinfo.username},secretKey,{expiresIn: '30s'})res.send({status:200,message: '登录成功',token: token})res.send('POST request to the homepage')})5.将JWT字符串还原为JSON对象客户端每次东访问那些有权限接口的时候,都需要主动通过请求头中的Authorization字段,将Token字符串发送到服务器进行身份认证。此时,服务器可以通过express-jwt这个中间件,自动将客户端发送过来的Token解析还原成JSON对象:// 安装并导入JWT相关的包 分别是 jsionwebtoken 和 express-jwtconst expressjwt = require('express-jwt')const jsont = require('jsonwebtoken')// 定义一个secret密钥,建议将密钥命名为 secretKeyconst secretKey = 'itbnsadklsdbabsdalhnlk ^_^'// 初测将JWT字符串解析还原成JSON对象的中间件app.use(expressjwt({secret: secretKey,algorithms:['HS256']}).unless({path:[/^\/api\//]}))6.捕获解析JWT失败后产生的错误当使用express-jwt解析Token字符串时,如果客户端发送过来的Token字符串过期或不合法,会产生一个解析失败的错误,影响项目的正常运行。我们可以通过 Express的错误中间件,捕获这个错误并进行相关的处理,示例代码如下:app.use((err, req, res,next) => {if(err.name === 'UnauthorizedError'){return res.send({status:401,msg:'无效的token'})}res.send({status:500,message:'未知的错误'})})

如果觉得《node.js学习总结:node.js的内置模块 模块化 npm与包 express 前后端身份认证 JWT认证机制》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。