个人笔记,Node.js部分 | 您所在的位置:网站首页 › 按下tab键切换对象 › 个人笔记,Node.js部分 |
1.初识Node.js
Node.js是一个基于chrome v8引擎的JS运行环境 Node.js是JS的后端运行环境,无法调用DOM和BOM等浏览器内置api 在node中执行JS代码: 打开终端 → 输入 node 要执行的JS文件路径 切换所处目录命令 (也可以在目录地址栏输入cmd/在目录下shift+右键打开powershell): cd 需要切换到的路径 //如果要切换到不同盘符,要先输入 盘符: /终端中的快捷键: ↑键可以快速读取上一次命令 tab键可以快速补全路径 esc键可以清空当前命令 输入cls命令可以清空当前终端 / 2.fs文件系统模块fs模块是Node官方提供的,用来操作文件的模块 导入fs模块(官方提供,无需额外安装): const 模块名 = require(‘fs’) 1.读取指定文件内容语法: 模块名.readFile(‘路径’,[编码格式],回调函数) 回调函数有两个固定形参,err(失败的结果)和dataStr(成功所拿到的文本) //可改名 如果读取成功,err默认是null 如果读取失败,则err的值为错误对象,dataStr的值为undefined 2.指定文件写入内容语法: 模块名.writeFile(‘路径’,‘内容’[,编码格式,默认utf8],回调函数) 回调函数有一个固定形参,err(失败的结果)//可修改名字 文件写入成功,err的值为null 文件写入失败,err的值为错误对象 注意:原有的内容会被覆盖,可以生成没有的文件,不能生成没有的路径 3.fs模块动态拼接路径问题如果使用相对路径,代码在运行时,会执行node命令时所处的目录来动态拼接操作文件的路径,如果不在文件原本路径运行node,会产生报错 如果使用完整的路径防止问题发生,但会造成移植性差,不利于维护的问题 因此,在node中一般使用__dirname(当前文件所属目录) 例如:__dirname+‘/files/txt/1.txt’ 3.path路径模块path模块是官方提供的用来处理路径的模块 导入path模块(官方提供,无需额外安装): const 模块名 = require(‘path’) 1.路径拼接语法: path.join(路径1,路径2,……) 注意…/在语法中会抵消前一个路径的最深层 对于__dirname的使用一般也使用path.join语法 2.获取路径中的文件名语法: path.basename(‘路径’,[文件扩展名]) 返回路径中的最后一部分字符串 输入扩展名可以自动清除扩展名部分,只留文件名 3.获取路径中的文件扩展名语法: path.extname(‘路径’) 返回扩展名字符串 4.http模块http模块是node官方提供的,用来创建web服务器的模块 导入http模块(官方提供,无需额外安装): const 模块名 = require(‘http’) 1.服务器相关概念IP地址是互联网上每台计算机的唯一地址,类似于电话号码,ip地址的常见格式是a.b.c.d,每一部分都是0-255之间的十进制整数,互联网中的每台web服务器都有其独立的ip地址 域名与ip地址是一一对应的关系,这份关系存放在域名服务器中,使用者只需记忆域名即可访问对应的服务器 在一台电脑中可以运行很多web服务,每个web服务都对应着唯一的端口号,客户端发送过来的网络请求,通过端口号,可以准确地交给对应的web服务处理,实际运用中,80端口可以被省略 2.创建web服务器在导入http模块后,创建web服务器实例: const 服务器实例 = 模块名.createServer() 为服务器实例绑定request事件: 服务器实例.on(‘request’,(req,res)=>{ 回调函数体 }) 启动服务器: 服务器实例.listen(端口号,回调函数) req请求对象:访问客户端相关的数据或属性 主要的属性和方法有: req.url:客户端请求的url地址,从端口号后开始 req.method:客户端请求的类型,例如get,post res响应对象:访问服务器相关的数据或属性 主要的属性和方法有: res.end(内容):返回内容且结束访问,类比return 注意res.end返回中文时浏览器会显示乱码,要设置响应头: res.setHeader(‘Content-Type’, ‘text/plain;charset=utf-8’); text/plain无法识别标签,如果需要识别标签可以改为text/html 5.模块化模块化是解决一个复杂问题时,自顶向下逐层把系统划分成若干个模块的过程,对于整个系统而言,模块是可以组合,分解和更换的单元 代码模块化可以提高代码的复用性和可维护性,可以实现按需加载 1.Node.js中的模块Node中模块分为三大类,分别是: 内置模块:官方提供的模块,例如fs,path,http等。加载写名字即可 自定义模块:用户创建的js文件都是自定义模块。加载需要路径 第三方模块:第三方提供的模块,需要下载使用。加载写名字即可 实际开发中,使用require()方法可以自由加载模块,加载时会执行模块内的代码 Node中也有类似于函数作用域的模块作用域,在自定义模块中定义的变量,方法等,只能在当前模块内访问,防止了全局变量污染 2.module对象module对象中储存了当前模块有关的信息 在自定义模块中,可以使用module.exports对象将内部成员共享出去,在外界使用require接收时,得到的就是module.exports对象中的内容 在默认情况下,Node还提供了exports对象简化操作,但如果module.exports改变了指向的对象,exports对象不会改变,最后共享的结果还是以module.exports对象为准 3.Node中的模块化规范1.每个模块内部,moudle变量代表当前模块 2.module变量是一个对象,module.exports是对外的接口 3.require()方法用于加载模块 6.npm与包Node中,第三方模块又称为包,Node中的包都是免费且开源的,供第三方免费下载使用 包是基于内置模块封装出来的,提供了更高级,更方便的api,提高开发效率 www.npmjs.com 是全球最大的包共享平台,可以在其中搜索包 registry.npmjs.org 使用包管理工具,用来下载所需的包 要安装包,需要在终端中使用命令: npm i 完整的包名称 如果需要安装指定版本的包: npm i 完整的包名称@版本号 包的版本号代表着(前面的版本号增长,后面归0):大版本.功能版本.bug修复版本 项目根目录中,又一个叫做package.json的包管理配置文件,记录一些例如项目名称,版本号,项目描述,所用的包,开发用到的包,开发和部署都用到的包等等 在多人协作的时候,第三方包的体积过大,因此要剔除node_modules目录(使用.gitignore),使用package.json记录安装的包,让合作者自行下载包 快速创建包管理配置文件: npm init -y 上述命令只能在英文目录下运行,不能使用中文,不能包含空格(当前目录即可) 用npm install命令时会自动写入包的信息在dependencies节点中 自动安装包管理配置文件里的包: npm install(或者i) 即可直接一次安装所有记录的包 卸载包(会从配置文件内移除): npm uninstall 包名 当一个包只在项目开发阶段会用到,可以把这些包记录到devDependencies中 npm i 包名 -D 下包速度慢解决: 使用淘宝npm镜像服务器: 检查当前下包源: npm config get registry 下包源切换成淘宝npm镜像服务器: npm config set registry=https://registry.npm.taobao.org 检查是否下载成功: npm config get registry 还可以使用nrm快速切换: 安装nrm: npm i nrm -g 查看可用镜像源: nrm ls 切换镜像源: nrm use 服务器简称 1.包的分类项目包: 安装到node_modules目录的包都是项目包 分别有开发依赖包(开发时才用得到)和核心依赖包(开发和上线后都用得到) 全局包: 当安装时添加 -g 参数,则会把包安装为全局包 全局包安装到C:\Users\用户目录\AppData\Roaming\npm\node_ modules目录下 卸载也需要添加-g参数 2.i5ting_toc包可以把md文档转化为html页面 使用语法: i5ting_toc -f 需要转换的md文件路径 -o 3.发布包:创建好包的根目录后要创建三个文件: package.json(包管理配置文件): “nane”:“包名” “version”:“版本号” “main”:“入口文件” “description”:“简要描述包的作用” “keywords”:[“检索词1”,“检索词2”,“检索词3”] “license”:“ISC” //开源协议 index.js(包的入口文件) README.md(包的说明文档): 安装方式,导入方式,功能,开源协议 在终端中登录npm: npm login 用户名 密码(输入不显示) 邮箱 注意:发布包之前要切换到官方服务器,包名不能与他人相同 在切换到包的根目录后,运行: npm public 删除已发布的包(只能在72小时之内删除,24小时内不能重复发布): npm unpublish 包名 --force 4.模块的加载机制模块在加载一次后会被缓存,多次调用会优先在缓存中加载,提高加载效率 内置模块的加载优先级最高,当有其他包重复名称时,require加载的永远是内置模块 加载自定义模块时,一定要使用./或…/这样的路径标识符进行加载,否则node会将其认为是内置模块或第三方模块加载 在加载自定义模块未输入扩展名时,node会自动按以下顺序加载文件: 按原文件名加载→按照.js加载→按照.json加载→按照.node加载→终端报错 在加载第三方模块时,node会从其同级node_modules目录下搜索,若未找到,会依次向上级目录node_modules目录下查找 7.expressexpress是第三方的,类似http模块的web服务器创建平台,可以更便捷的创建服务器 1.用express创建服务器在导入express后,创建服务器: const 服务器名 = express() 启动服务器: 服务器名.listen(端口号,回调函数) 2.用express监听get/post请求监听get请求: 服务器名.get(‘请求url’,回调函数(有req和res两个形参)) 监听post请求: 服务器名.post(‘请求url’,回调函数(有req和res两个形参)) express提供了更多req和res操作: res.send(内容):发送内容,如果是对象会转为JSON格式 req.query:客户端发送的查询字符串(例如:?name=zs),默认情况下是空对象 req.params:匹配:后的动态参数,默认情况下是空对象(例如:/user/:id在客户端发送/user/1时,req.params里的id:1),动态参数可以是多个 3.托管静态资源创建静态资源服务器: 服务器名.use(express.static(‘静态资源目录’)) 之后就可以访问静态资源目录中的所有文件,存放静态资源的根目录名不会出现在url中 如果需要托管多个,只需要多次调用express.static()函数即可,访问时,会根据目录的添加顺序查找所需的文件 挂载路径前缀: express.static(‘/路径前缀’,‘静态资源目录’) 最后访问时会变成:url地址/路径前缀/静态资源 4.nodemonnodemon工具可以在修改项目文件代码后,自动重启项目,极大地方便了开发和调试 在启动项目时,只需把node替换为nodemon即可: nodemon 项目名 5.路由路由就是映射关系,在express中,路由由请求的类型,url地址和处理函数组成: 服务器名.请求类型(‘请求的url地址’,处理函数(有req和res两个形参)) 为了对路由进行模块化的管理,express不建议将路由直接挂载在服务器上,而是推荐将路由抽离为单独的模块: 创建路由模块对应的js文件 然后使用express.Router()函数创建路由对象: 路由对象.请求类型(‘请求的url地址’,处理函数(有req和res两个形参)) 向路由对象是挂载具体的路由,随后使用module.exports向外共享路由对象 最后在主文件中导入模块且注册路由模块: 服务器名.use(路由对象) 路由模块也可以添加前缀: 服务器名.use(‘/前缀地址’,路由对象) 6.中间件中间件特指业务流程中的中间处理环节,Node中按照书写顺序调用,一定要写在路由前 中间件在实际开发中,多个中间件共享同一个req和res,我们可以在上游的中间件中统一在req或res对象添加自定义的属性或方法,供下游的中间件或路由使用(组件化) express中间件本质上就是一个处理函数,格式如下: 服务器名.请求类型(‘请求的url函数’,处理函数(有req,res和next三个参数)) next参数的作用: next参数本质上是一个函数,是实现多个中间件连续调用的关键 调用next()就是把流转关系交给下一个中间件或者路由处理,一定要调用 全局中间件: 客户端发起任何请求(任何请求类型和页面都会触发)都会触发的中间件,格式如下: 服务器名.use(全局中间件函数) 局部中间件: 服务器名.请求类型(‘请求的url函数’,中间件函数1,中间件函数2,……,处理函数(有req和res两个参数)) 1.中间件的分类express官方把中间件分为了五大类: ①应用级别的中间件 通过服务器.use()/服务器get()/服务器.post()绑定到服务器实例上的中间件都称为应用级别的中间件 ②路由级别的中间件 绑定到express.Router()上的中间件成为路由级别的中间件 ③错误级别的中间件(防止程序完全崩溃,正常执行错误中间件) 专门捕获项目中的一场错误,防止项目异常崩溃的问题,必须按顺序包括四个形参:err,req,res,next 其中err.message是错误相关的内容 必须注册在所有路由之后 ④express内置中间件 express内置了三个常见中间件: express.static() //快速托管静态资源内置中间件 express.json()//解析json格式的请求体请求 express.urlencoded()//解析url-encoded格式的请求体数据 使用方式: 如果客户端发送的是类似JSON格式的请求体数据,使用 req.body接收,如果没有配置解析表单的中间件,默认等于undefined ⑤第三方中间件 非内置的,第三方提供的中间件 7.跨域使用CORS完成接口跨域,CORS是express第三方中间件,由一系列http响应头组成,这些响应头决定浏览器是否阻止前端js代码跨域获取资源,使用方式: 使用npm i cors安装 在路由之前配置cors: const cors = require(‘cors’) 全局注册cors: 服务器名.use(cors()) 注意cors有兼容性问题,在ie9之前的浏览器无法正常使用 默认情况下cors仅支持客户端发起GET,POST,HEAD请求 如果需要支持其他请求,需要配置: res.setHeader(‘Access-Control-Allow-Methods’,‘允许的请求方式1,方式2……’) 如果允许所有的请求,则直接填入* 1.CORS的请求分类①简单请求: 如果请求方式属于GET,POST和HEAD三者之一,并且http头部信息不超过默认规定的范围内。 客户端与服务器只会发生一次请求 ②预检请求: 请求方式属于默认以外的方式,或者包含自定义头部字段,或者发送了application/JSON格式的数据 预检请求就是,在正式通信前,浏览器会先发送option请求进行预检,如果服务器允许且成功响应,才会发送真正的请求,并携带真实数据 客户端和服务器会发起两次请求 2.jsonp接口编写浏览器端通过 JSONP只支持GET请求,不属于真正的Ajax请求,因为没有使用XHR对象 JSONP的接口一定要写在CORS中间件前 格式: 服务器名.get(‘请求的url’,(req,res) =>{ //首先获取客户端发送的回调函数的名字 const 回调函数名 = req.query.callback //定义要通过JSONP返回的数据 const 数据名 = {数据} //将数据和函数名拼接成字符串 const 字符串名 = ${回调函数名}(${JSON.stringify(数据名)}) //发送回客户端 res.send(字符串名) }) 8.数据库数据库是用来组织,存储和管理数据的仓库 常见的数据库有很多种,常见的有: MySQL,Oracle(收费),SqlServer(收费),MongoDB(免费or收费) 前三个数据库属于传统型数据库,设计理念相同,用法比较类似 MongoDB是新型数据库,在一定程度上弥补了传统数据库的缺陷但不是替代关系 其中MySQL是开源免费(有收费版)的数据库,使用广泛,流行度高 传统型数据库的数据组织结构,类似于Excel中的数据组织结构 Excel中:工作簿包含工作表包含数据行和列 传统型数据库中:数据库包含数据表包含数据行和字段 一般情况下,每个项目对应着独立的数据库,不同的数据要储存到数据库的不同的表中,例如:图书存在books,用户储存到users 表中储存哪些信息由字段决定,例如:user表有ID,username,password字段 1.MySQL对开发人员来说,只需要MySQL server和MySQL workbench两个软件即可 MySQL server用来提供数据储存和服务,MySQL workbench用来可视化管理MySQL 正确安装MySQL后,进入数据库,选择上方从左往右第四个工具创建新的数据库,name不能包含中文和空格,空格尽量使用_替代 创建数据表: 在数据库中右键tables节点,选择create,输入name(表名),comments(注释可选),column(字段) datatype分类: int — 整数 varchar(最大长度) — 字符串 tinyint(1) — 布尔值 字段特殊标识,从左往右: PK — 主键(唯一标识) NN — 非空 UQ — 值唯一 bin —二进制数据 AI — 值自动递增 zf — 自动填充0 g — 生成列 写入数据: 在创建的表上右键,选择select rows - limit1000 2.SQLsql是专门用来访问和处理数据库的编程语言,可以让我们以代码的形式,操作数据库里的数据,只能在传统型数据库中使用,语句对大小写不敏感 sql可以增删改查数据库的数据,还可以创建新数据库,表等等 在sql中 --表示注释 1.select语句用于从表中查询数据,格式: SELECT 列名称1,列名称2 FROM 表名称 全部查询在列名称填入* 2.insert语句用于在表中插入数据 插入数据行,语句: insert into 表名(列1,列2,……) values(值1,值2) 3.update语句用于在表中更新数据,语法: update 表名 set 列名1=新数据1,列名2,新数据2 where 筛选项(例如:id=1) 4.delete语句用于在表中删除数据,语法: delete form 表名称 where 筛选项 5.where子句用于限定选择的标准,在select,update,delete语句中都可以使用 可以在where子句中使用的运算符: =(等于)和(不等于,也可以写成!=) =(大于和大于等于) between(在某个范围内) like(某种搜索模式) 6.and和or运算符and和or运算符可以在where子句中把两个或多个条件结合起来 例如:delete from users where id=1 and/or status=1 and相当于js中的&&(与)运算符,or相当于js中的||(或)运算符 7.order by语句根据指定的列对结果进行排序,默认按照从小到大(asc)排列 如果要修改为从大到小,需要使用DESC关键字 例如:select * from users order by status desc 如果需要多重排序: select * from users order by status desc,username asc (先按照status降序排序,再按照username字母顺序升序排序) 8.count(*)函数用于返回查询结果的总条数: **select***count()**form users where status = 0 9.as关键字为查询出来的列设定别名 select count(*)AS 别名from users where status=0 3.在Node中使用mysql使用npm i mysql进行安装模块 引入:const mysql = require(‘mysql’) 配置:const 数据库名 = mysql.createPool({ host:‘数据库ip地址’ user:‘数据库账号’ password:‘密码’ database:‘指定操作的数据库名’ }) 执行sql语句: 数据库名.query(‘sql语句’,回调函数(有err(错误信息)和results(返回结果)两个形参)) 使用node筛选数据,得到的是数据为对象的数组 使用node插入数据,可以在sql语句中使用占位符?,之后用数组赋值,例如: 数据库.query(insert into users(username,password) values**(?,?),[‘用户名’,‘密码’]****,回调函数)** 这样可以方便通过客户提交的数据导入数据库 当results.affectedRows = 1时,插入数据成功 便捷插入数据: 如果数据对象的每个属性与数据表的字段一一对应,则可以通过以下方式快速插入 例如: const user = {username:‘zs’,password:‘123456’} const sqlStr = ‘insert into users set**?****’** 数据库.query(sqlStr,user,回调函数) 使用node更新数据: 与创建类似,update也可以使用占位符: 数据库.query{‘update users set username=?,password=?where id=?’[user.username,user.password,user.id],回调函数} 当results.affectedRows = 1时,更新数据成功 更新数据的便捷方式也和插入类似: sql语句:update users set**?where id=?** 要求导入的对象和数据表字段一一对应 使用node删除数据: 在删除数据时,尽量使用id这样的唯一性标识来删除对应的数据: 数据库.query(‘delete from users where id = ?’,user.id,回调函数) 标记删除: 为了保证用户不是误触删除,推荐使用标记删除的形式来模拟删除操作,模拟删除就是类似于status这样的字段,在用户点击删除时,使用update来标记用户删除的数据 9.session认证http的每次请求都是独立的,如果连续多次发生请求,服务器不会保留每次的状态,因此要通过cookie记录用户状态 cookie是储存在用户浏览器中一段不超过4kb的字符串,由一个名称,一个值,和其他几个用于控制cookie有效期,安全性,适用范围的可选属性组成 不同域名下的cookie是独立的,在发起请求时,浏览器会自动发送对应域名下的未过期的cookie 客户端第一次请求服务器的时候,服务器通过响应头的方式向客户端发送一个身份认证的cookie,之后当浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的cookie通过请求头的方式发送给服务器 cookie不具有安全性,cookie储存在浏览器中,且浏览器提供了读写cookie的api,因此隐私数据不应该通过cookie传输。 1.session认证机制大多数时候用于非跨域解决方案,用户的信息保存在服务器端 在npm中安装express-session中间件 let session = require(‘express-session’) 服务器名.use(session({ secret:‘描述’, resave:false, //固定写法 saverUninitialized:true //固定写法 })) 在session中存/取数据: req.session来访问和使用session对象 例如:req.session.user = req.body.username if(!req.session.islogin){} 清空session(例如用户退出登录): req.session.destroy 2.jwt认证机制session的认证机制需要配合cookie才能实现,但cookie默认不支持跨域访问,因此需要做很多额外的配置,才能实现session跨域,因此jwt认证机制出现了 jwt是最热门的跨域认证机制 jwt的储存方式是将用户的信息通过token字符串的形式储存在客户端浏览器(localstorage或sessionstorage)中,服务器通过还原token字符串的形式来认证用户身份 jwt由三部分组成:头部(header).有效荷载(payload).签名(signature) 在其中,payload才是真正的加密后的用户信息,而header和signature是安全性相关的部分 jwt使用: 当客户端收到服务器返回的jwt后,上传推荐的做法是吧jwt放在http请求头的Authorization中: Authorization:Bearer 使用jwt: 使用jsonwebtoken(生成字符串)和express-jwt(解析字符串)两个包 使用require分别导入 为了保证安全性,我们要定义secret秘钥加密jwt字符串: const secretKey = ‘任意字符串’ 生成jwt字符串: jwt.sign({用户信息对象},secretKey,{expiresIn(有效期):‘60s’}) 第三部分又称为配置对象 还原jwt: 服务器可以通过express-jwt来自动解析token,转换成json对象 express-jwt最新版本需要配置algorithms算法,一般默认是HS256,配置格式 服务器名.use(jwt中间件.expressjwt{secret:secretKey,algorithms: [‘HS256’]}).unless({path:[不需要访问权限的接口]}) 配置成功后,就可以使用req.auth来访问从jwt字符串解析出来的用户信息: 在用户的密码加密: 导入bcryptjs包,调用bcrypt.hashSync(明文密码,随机盐的长度) 用户的密码验证: 使用if,else校验复杂难懂,因此引入第三方joi包让校验更加方便 使用npm i joi安装包 |
CopyRight 2018-2019 实验室设备网 版权所有 |