NodeJS
Buffer
概念
Buffer是一个类似于数组的对象,用于表示固定长度的字节序列
Buffer本质是一段内存空间,专门用来处理二进制数据
特点
- Buffer大小固定且无法调整
- Buffer性能较好,可以直接对计算机内存进行操作
- 每个元素的大小为1字节(byte)
使用
创建Buffer
1 | //创建了一个长度为 10 字节的 Buffer,相当于申请了 10 字节的内存空间,每个字节的值为 0 |
Buffer与字符串的转化
可以借助toString方法将Buffer转为字符串
1 | let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]); |
Buffer的读写
Buffer可以直接通过[]的方式对数据进行处理。
1 | // 读取 |
注意:如果修改的数值超过255,则超过8位数据会被舍弃
一个uff-8的字符一般占3个字节
fs模块
fs全称为file system,称之为文件系统,是Node.js中的内置模块,可以对计算机中的磁盘进行操作。
文件写入
文件写入就是将数据保存到文件当中。
| 方法 | 说明 |
|---|---|
| writeFile | 异步写入 |
| writeFileSync | 同步写入 |
| appendFile / appendFileSync | 追加写入 |
| createWriteStream | 流式写入 |
writeFile异步写入
语法:
1 | fs.writeFile(file, data[, options], callback) |
参数说明
- file 文件名
- data 待写入的数据
- options 选项设置(可选)
- callback 写入回调
返回值:undefined
代码示例:
1 | // require 是 Node.js 环境中的'全局'变量,用来导入模块 |
writeFileSync同步写入
语法:
1 | fs.writeFileSync(file, data[, options]) |
参数与fs.writeFile大体一致,只是没有callback参数
返回值:undefined
代码示例:
1 | try{ |
Node.js中的磁盘操作是由其他线程完成的,结果的处理有两种模式
- 同步处理 javascript主线程会等待其他线程的执行结果,然后再继续执行主线程的代码
- 异步处理 javascript主线程不会等待其他线程的执行结果,直接执行后续的主线程代码
appendFile / appendFileSync追加写入
appendFile作用是在文件尾部追加内容,appendFile语法于writeFile语法完全相同
语法:
1 | fs.appendFile(file, data[, options], callback) |
返回值:二者都会undefined
示例代码:
1 | fs.appendFile('./座右铭.txt','择其善者而从之,其不善者而改之。', err => { |
createWriteStream流式写入
语法:
1 | fs.createWriteStream(path[, options]) |
参数说明
- path 文件路径
- options 选项配置(可选)
返回值:Object
代码示例:
1 | let ws = fs.createWriteStream('./观书有感.txt'); |
程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数。
流式写入方式适用于大文件写入或者频繁写入的场景,writeFile适合于写入频率较低的场景。
写入文件的场景
文件写入在计算机中是一个非常常见的操作,下面的场景都用到了文件写入
- 下载文件
- 安装软件
- 保存程序日志,入Git
- 编辑器保存文件
- 视频录制
当需要持久化保存数据的时候,应该想到文件写入
文件读取
文件读取顾名思义,就是通过程序从文件中取出其中的数据,可以使用如下几种方式:
| 方法 | 说明 |
|---|---|
| readFile | 异步读取 |
| readFileSync | 同步读取 |
| createReadStream | 流式读取 |
readFile异步读取
语法:
1 | fs.readFile(path[, options], callback) |
参数说明:
- path 文件路径
- options 选项配置
- callback 回调函数
返回值:undefined
示例代码:
1 | //导入 fs 模块 |
readFileSync同步读取
语法:
1 | fs.readFileSync(path[, options]) |
参数说明:
- path 文件路径
- options 选项配置
返回值:string | Buffer
代码示例:
1 | let data = fs.readFileSync('./座右铭.txt'); |
createReadStream流式读取
语法:
1 | fs.createReadStream(path[, options]) |
参数说明:
- path 文件路径
- options 选项配置(可选)
代码示例:
1 | //创建读取流对象 |
读取文件应用场景
- 电脑开机
- 程序运行
- 编辑器打开文件
- 查看图片
- 播放视频
- 播放音乐
- Git查看日志
- 上传文件
- 查看聊天记录
文件移动与重命名
在Node.js中,我们可以使用rename或renameSync来移动或重命名文件或文件夹
语法:
1 | fs.rename(oldPath, newPath, callback) |
参数说明:
- oldPath 文件当前的路径
- newPath 文件新的路径
- callback 操作后的回调
代码示例:
1 | fs.rename('./观书有感.txt', './论语/观书有感.txt', (err) =>{ |
文件删除
在Node.js中,我们可以使用unlink、unlinkSync、rm、rmSync来删除文件
语法:
1 | fs.unlink(path, callback) |
参数说明:
- path 文件路径
- callback 操作后的回调
代码示例:
1 | const fs = require('fs'); |
文件夹操作
借助Node.js的能力,可以对文件夹进行创建、读取、删除等操作
| 方法 | 说明 |
|---|---|
| mkdir / mkdirSync | 创建文件夹 |
| readdir / readdirSync | 读取文件夹 |
| rmdir / rmdirSync | 删除文件夹 |
创建文件夹
语法:
1 | fs.mkdir(path[, options], callback) |
参数说明:
- path 文件夹路径
- options 选项配置(可选)
- calback 操作后的回调
示例代码:
1 | fs.mkdir('./page', err => { |
读取文件夹
语法:
1 | fs.readdir(path[, options], callback) |
参数说明:
- path 文件夹路径
- options 选项配置(可选)
- callback 操作后的回调
示例代码:
1 | //异步读取 |
删除文件夹
语法:
1 | fs.rmdir(path[, options], callback) |
参数说明:
- path 文件夹路径
- options 选项配置(可选)
- callback 操作后的回调
示例代码:
1 | //异步删除文件夹 |
查看资源状态
在Node.js中,可以使用stat或statSync来查看资源的详细信息
语法:
1 | fs.stat(path[, options], callback) |
参数说明:
- path 文件夹路径
- options 选项配置(可选)
- callback 操作后的回调
示例代码:
1 | //异步获取状态 |
结果值对象结构:
- size 文件体积
- birthtime 创建时间
- mitime 最后修改时间
- isFile 检测是否为文件
- isDirectory 检测是否为文件夹
- …
__dirname
__dirname与require类似,都是Node.js环境中的’全局变量’
__dirname保存着当前文件所在目录的绝对路径,可以使用__dirname与文件名拼接成绝对路径
代码示例:
1 | let data = fs.readFileSync(__dirname + '/data.txt'); |
path模块
path模块提供了操作路径的功能,如下为几个常用的API:
| API | 说明 |
|---|---|
| path.resolve | 拼接规范的绝对路径 |
| path.sep | 获取操作系统的路径分隔符 |
| path.parse | 解析路径并返回对象 |
| path.basename | 获取路径的基础名称 |
| path.dirname | 获取路径的目录名 |
| path.extname | 获取路径的扩展名 |
代码示例:
1 | const path = require('path'); |
HTTP协议
一、概念
HTTP(hypertext transport protocol)协议;中文叫超文本传输协议
是一种基于TCP/IP的应用层通信协议
这个协议详细规定了浏览器和万维网服务器之间互相通信的规则
协议中主要规定了两个方面的内容
- 客户端:用来向服务器发送数据,可以被称之为请求报文
- 服务端:向客户端返回数据,可以被称之为响应报文
报文:可以简单理解为就是一堆字符串
二、请求报文的组成
- 请求行
- 请求头
- 空行
- 请求体
三、HTTP的请求行
- 请求方法(get、post、put、delete等)
- 请求URL(统一资源定位器)
- 例如:http://www.baidu.com:80/index.html?a=100&b=200#logo
- http:协议(https、ftp、ssh等)
- <www.baidu.com> 域名
- 80 端口号
- /index.html 路径
- a=100&b=200 查询字符串
- #logo 哈希(锚点链接)
- 例如:http://www.baidu.com:80/index.html?a=100&b=200#logo
- HTTP协议版本号
四、HTTP请求头
格式:【头名:头值】
常见的请求头有:
| 请求头 | 解释 |
|---|---|
| Host | 主机名 |
| Connection | 链接的设置 keep-alive(保持连接);close(关闭连接) |
| Cache-Control | 缓存控制 max-age = 0 (没有缓存) |
| Upgrade Insecure Requests | 将网页中的http请求转化为https请求(很少用)老网站升级 |
| User-Agent | 用户代理,客户端字符串标识,服务器可以通过这个标识来识别这个请求来自 哪个客户端 ,一般在PC端和手机端的区分 |
| Accept | 设置浏览器接收的数据类型 |
| Accept-Encoding | 设置接收的压缩方式 |
| Accept Language | 设置接收的语言 q=0.7 为喜好系数,满分为1 |
| Cookie |
五、HTTP请求体
请求体内容的格式是非常灵活的
(可以是空)==> GET请求
(也可以是字符串,还可以是JSON) ===> POST请求
六、响应报文的组成
- 响应行
- HTTP/1.1 200 OK
- HTTP/1.1:HTTP协议版本号
- 200:响应状态码 404 Not Found 500 Internal Server Error
- OK:响应状态描述
- HTTP/1.1 200 OK
- 响应头
- Cache-Control:缓存控制 private 私有的,只允许客户端缓存数据
- Connection 链接设置
- Content-Type:text/html;charset=utf-8 设置响应体的数据类型以及字符集,响应体为html,字符集utf-8
- Content-Length:响应体的长度,单位为字节
- 空行
- 响应体
响应体内容的类型是非常灵活的,常见的类型有HTML、CSS、JS、图片、JSON
七、创建HTTP服务
使用Node.js创建HTTP服务
操作步骤
1 | //1. 导入 http 模块 |
http.createServer 里的回调函数的执行时机: 当接收到 HTTP 请求的时候,就会执行
测试
直接使用浏览器请求对应的端口
1 | http://127.0.0.1:9000 |
注意事项
响应内容中文乱码的解决方法(在createServer的回调函数中调用)
1 | response.setHeader('content-type','text/html;charset=utf-8'); |
八、获取HTTP请求报文
想要获取请求的数据,需要通过request对象
| 含义 | 语法 | 重点掌握 |
|---|---|---|
| 请求方法 | request.method | * |
| 请求版本 | request.httpVersion | |
| 请求路径 | request.url | * |
| URL路径 | request(‘url’).parse(request.url).pathname | * |
| URL查询字符串 | request(‘url’).parse(request,url,true).query | * |
| 请求头 | request.headers | * |
| 请求体 | request.on(‘data’,function(chunk){}) request.on(‘end’,function(){}) |
注意事项:
- request.url只能获取路径以及查询字符串,无法获取URL中的域名以及协议的内容
- request.headers将请求信息转化成一个对象,并将属性名都转化成了小写
- 关于路径:如果访问网站的时候,只填写了IP地址或是域名信息,此时请求的路径为**/**
- 关于favicon.ico:这个请求属于浏览器自动发送的请求
九、设置HTTP响应报文
| 作用 | 语法 |
|---|---|
| 设置响应状态码 | response.statusCode |
| 设置响应状态描述 | response,statusMessage |
| 设置响应头信息 | response.setHeader(‘头名’, ‘头值’) |
| 设置响应体 | response.write(‘xx’) response.end(‘xx’) |
1 | write 和 end 的两种使用情况: |
Node.js模块化
一、介绍
什么是模块化与模块
将一个复杂的程序文件依据一定规则拆分成多个文件的过程称之为模块化
其中拆分的每个文件就是一个模块,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用
什么是模块化项目
编码时是按照模块一个一个编码的,整个项目就是一个模块化的项目
模块化的好处
- 防止命名冲突
- 高复用性
- 高维护性
二、模块暴露数据
模块初体验
1.创建me.js
1 | // 声明函数 |
2.创建index.js
1 | // 导入模块 |
暴露数据
模块暴露数据的方式有两种
- module.exports = value;
- exports.name = value;
使用时有几点注意:
- module.exports可以暴露任意数据
- 不能使用exports = value的形式暴露数据,模块内部module与exports的隐式关系exports = module.exports = {},require返回的是目标模块中module.exports的值
三、导入(引入)模块
在模块中使用require传入文件路径即可引入文件
1 | const test = require('./me.js'); |
require使用的一些注意事项:
- 对于自己创建的模块,导入时路径建议写相对路径,且不能省略./和../
- js和json文件导入时可以不用写后缀,c/c++编写的node扩展文件也可以不写后缀,但是一般用不到
- 如果导入其他类型的文件,会以js文件进行处理
- 如果导入的路径是个文件夹,则会首先检测该文件下下package.json文件中main属性对应的文件,如果存在则导入,反之则会报错。如果main属性不存在,或者pachage.json不存在,则会尝试导入文件夹下的index.js和index.json,如果还是没找到,就会报错
- 导入node.js内置模块时,直接require模块的名字即可,无需加./和../
四、导入模块的基本流程
- 将相对路径转为绝对路径,定位目标文件
- 缓存检测
- 读取目标文件代码
- 包裹为一个函数并执行,通过anguments.callee.toString()查看自执行函数
- 缓存模块的值
- 返回module.exports的值
包管理工具
一、概念介绍
包是什么
【包】英文单词是package,代表了一组特定功能的源码的集合
包管理工具
管理【包】的应用软件,可以对【包】进行下载安装、更新、删除、上传等操作
借助包管理工具,可以快速开发项目,提升开发效率
包管理工具是一个通用的概念,很多变成语言都有包管理工具,所以掌握好包管理工具很重要
常用的包管理工具
- npm
- yarn
- cnpm
二、npm
npm全称是Node Package Manager,即Node的包管理工具
npm是node.js官方内置的包管理工具
npm的安装
node.js在安装时会自动安装npm。
可以通过npm -v查看版本号,如果显示版本号则说明安装成功
npm的基本使用
初始化
创建一个空目录,然后以此目录作为工作目录启动命令行工具,执行npm init
npm init命令的作用是将文件夹初始化为一个【包】,交互式创建package.json文件
package.json是包的配置文件,每个包都必须要有package.json
package.json内容示例
1 | { |
初始化的过程中还有一些注意事项:
- package name不能使用中文、大写,默认值是文件夹的名称,所以文件夹名称也不能使用中文和大写
- version要求x.x.x的形式定义,x必须是数字,默认值是1.0.0
- ISC证书与MIT证书功能上是相同的。
- package.json可以手动创建和修改
- 使用npm init -y或者npm init –yes极速创建package.json(前提是文件夹不能是中文及大写)
搜索包
搜索包的方式有两种
- 命令行【npm s/search 关键字】
- 网站搜索,http://www.npmjs.com/
下载安装包
通过npm install或npm i命令安装包
运行后文件夹下会增加两个资源
- node_module文件夹存放下载的包
- package-lock.json包的锁文件,用来锁定包的版本
require导入npm包基本流程
- 在当前文件夹下node_modules中寻找同名的文件夹
- 在上级目录中下的node_module中寻找同名的文件夹,直至找到磁盘根目录
生产环境与开发环境
开发环境是程序员专门用来写代码的环境,一般是指程序员的电脑,开发环境的项目一般只能程序员自己访问。
生产环境是项目代码正式运行的环境,一般是指正式的服务器电脑,生产环境的项目一般每个客户都可以访问。
生产依赖与开发依赖
我们可以在安装时设置选项来区分依赖的类型,目前分为两类:
| 类型 | 命令 | 补充 |
|---|---|---|
| 生产依赖 | npm i -S uniq npm i –save uniq |
-S等效于 –save,-S是默认选项 包信息保存在package.json中dependencies属性 |
| 开发依赖 | npm i -D less npm i –save-dev less |
-D等效于 –save-dev 包信息保存在package.json中devDependencies属性 |
简单说就是,开发依赖只有在开发阶段才会使用到的依赖包,而生产依赖则是开发阶段和最终上线运行阶段都用的到的依赖包
全局安装
可以执行安装选项**-g**进行全局安装
全局安装完成之后就可以在命令行的任何位置运行nodemon命令
该命令的作用是自动重启node应用程序
说明:
- 全局安装的命令不受工作目录位置影响
- 可以通过npm root -g查看全局安装包的位置
- 不是所有的包都适合全局安装,只有全局类的工具才适合,可以通过查看包的官方文档来确定安装方式
修改windows的执行策略
windows默认不允许nom全局命令执行脚本文件,所以需要修改执行策略
- 以管理员身份打开powershell命令行
- 键入关键命令set-ExecutionPolicy remoteSigned
- 键入A然后敲回车
- 如果不生效,可以尝试重启vscode
环境变量Path
Path是操作系统的一个环境变量,可以设置一些文件夹的路径,在当前工作目录下找不到可执行文件时,就毁在环境变量Path的目录中挨个的查找,如果找到则执行,如果找不到就会报错
补充说明:
- 如果希望某个程序在任何工作目录下都能正常运行,就应该将该程序的所在目录配置到环境变量Path中
- windows下查找命令的所在位置
- cmd命令行中执行where nodemon
- powershell命令行执行get-command nodemon
安装包依赖
在项目协作中有一个常用的命令就是npm i,通过该命令可以依据package.json和package-lock.json的依赖声明安装项目依赖
1 | npm i |
安装指定版本的包
项目中可能会遇到版本不匹配的情况,有时就需要安装指定版本的包,可以使用下面的命令
1 | ## 格式 |
删除依赖
项目中可能需要删除某些不需要的包,可以使用下面的命令
1 | ## 局部删除 |
配置命令别名
通过配置命令别名可以更简单的执行命令
配置package.json中的scripts属性
1 | { |
配置完成后,可以使用别名执行命令
1 | npm run server |
不过start别名比较特别,使用时可以省略run
1 | npm start |
三、cnpm
介绍
cnpm是一个淘宝构建的npmjs.com的完整镜像,也称为淘宝镜像。
cnpm服务部署在国内阿里云服务器上,可以提高包的下载速度。
官方也提供了一个全局工具包cnpm,操作命令与npm大体相同。
安装
可以通过npm来安装cnpm工具
1 | npm install -g cnpm --registry=https://registry.npmmirror.com |
操作命令
| 功能 | 命令 |
|---|---|
| 初始化 | cnpm init / cnpm init |
| 安装包 | cnpm i uniq cnpm i -S uniq cnpm i -D uniq cnpm i -g nodemon |
| 安装项目依赖 | cnpm i |
| 删除 | cnpm r uniq |
npm配置淘宝镜像
用npm也可以使用淘宝镜像,配置的方式有两种
- 直接配置
- 工具配置
直接配置
执行下方的命令:
1 | npm config set registry https://registry.npmmirror.com/ |
工具配置
使用nrm配置npm的镜像地址npm registry manager
- 安装nrm: npm i -g nrm
- 修改镜像:nrm use taobao
- 检查是否配置成功:npm config list
检查registry地址是否为https://registry.npmmirror.com/,如果是则表明成功
四、yarn
yarn介绍
yarn是有Facebook在2016年推出的新的Javascript包管理工具,官方网址:https://yarnpkg.com
yarn特点
yarn官方宣称的一些特点
- 速度超快:yarn缓存了每个下载过的包,所以再次使用时无需重复下载。同时利用并行下载以最大化资源利用率,因此安装速度更快
- 超级安全:在执行代码前,yarn会通过算法校验每个安装包的完整性
- 超级可靠:使用详细、简洁的锁文件格式和明确的安装算法,yarn能够保证在不同系统上无差异的工作
yarn安装
可以使用npm安装yarn
1 | npm i -g yarn |
yarn常用命令
| 功能 | 命令 |
|---|---|
| 初始化 | yarn init / yarn init -y |
| 安装包 | yarn add uniq 生产依赖 yarn add less –dev 开发依赖 yarn global add nodemon 全局安装 |
| 删除包 | yarn remove uniq 删除项目依赖包 yarn global remove nodemon 删除全局包 |
| 安装项目依赖 | yarn |
| 运行命令别名 | yarn <别名> # 不需要添加run |
yarn全局安装包的位置可以通过yarn global bin来查看
yarn配置淘宝镜像
1 | yarn config set registry https://registry.npmmirror.com/ |
可以通过yarn config list查看yarn的配置项
npm和yarn的选择
可以根据不同的项目场景进行选择
- 个人项目
- 如果是个人项目,哪个工具都可以,可以根据自己的喜好来选择
- 公司项目
- 如果是公司要根据项目代码来选择,可以通过锁文件判断项目的包管理工具
- npm的锁文件未package-lock.json
- yarn的锁文件为yarn.lock
- 如果是公司要根据项目代码来选择,可以通过锁文件判断项目的包管理工具
五、管理发布包
创建与发布
可以将自己开发的工具包发布到npm服务器上,方便自己和其他开发者使用
- 创建文件夹,并创建文件index.js,在文件中声明函数,使用module.exports暴露
- npm初始化工具包,package.json填写包的信息
- 注册账号:https://www.npmjs.com/signup
- 激活账号(一定要激活账号)
- 修改为官方的官方镜像(命令行中运行nrm use npm)
- 命令行下npm login填写相关用户信息
- 命令行下npm publish提交包
更新包
后续可以对自己发布的包进行更新,操作步骤如下
- 更新包中的代码
- 测试代码是否可用
- 修改package.json中的版本号
- 发布更新
1 | npm publish |
删除包
执行如下命令删除包
1 | npm unpublish --force |
删除包需要满足一定的条件
- 你是包的作者
- 发布小于24小时
- 大于24小时后,没有其他包依赖,并且每周小于300下载量,并且只有一个维护者
六、扩展内容
在很多语言中都有包管理工具,比如:
| 语言 | 包管理工具 |
|---|---|
| PHP | composer |
| Python | pip |
| Java | maven |
| Go | go mod |
| JavaScript | npm/yarn/cnpm/other |
| Ruby | rubyGems |
除了编程语言领域有包管理工具外,操作系统层面也存在包管理工具,不过这个包指的是【软件包】
| 操作系统 | 包管理工具 | 网址 |
|---|---|---|
| Centos | yum | https://packages.debian.org/stable/ |
| Ubuntu | apt | https://packages.ubuntu.com/ |
| MacOS | homebrew | https://brew.sh/ |
| Windows | chocolatey | https://chocolatey.org/ |
nvm
一、介绍
nvm全称Node Version Manager,顾名思义,是一个用来管理node版本的工具,方便切换到不同版本的Node.js
二、使用
nvm的使用非常简单,跟npm的使用方法类似
下载安装
下载地址:https://github.com.coreybutler/nvm-windows/releases
选择nvm-setup.exe即可下载
常用命令
| 命令 | 说明 |
|---|---|
| nvm list available | 显示所有可以下载的Node.js版本 |
| nvm list | 显示已安装的版本 |
| nvm install 18.12.1 | 安装18.12.1版本的Node.js |
| nvm install latest | 安装最新版本的Node.js |
| nvm uninstall 18.12.1 | 删除某个版本的Node.js |
| nvm use 18.12.1 | 切换到18.12.1的Node.js |
Express.js
一、express介绍
express是一个基于Node.js平台的极简、灵活的WEB应用开发框架,官方网址:https://www.expressjs.com.cn/
简单来说,express是一个封装好的工具包,封装了很多的功能,便于开发WEB应用(HTTP服务)
二、express使用
express下载
express本身是一个npm包,所以可以通过npm安装
1 | npm init |
express初体验
1.创建JS文件
1 | // 1.导入express |
2.命令行下执行该脚本
1 | node <文件名> |
3.然后在浏览器就可以访问https://127.0.0.1:3000/home
三、express路由
什么是路由
官方定义:路由确定了应用程序如何响应客户端对特定端点的请求
路由的使用
一个路由的组成有请求方法,路径和回调函数组成
express中提供了一系列的方法,可以很方便的使用路由,使用格式如下:
1 | app.<method>(path, callback) |
代码示例:
1 | // 引入express |
获取请求参数
express框架封装了一些API来方便获取请求报文中的数据,并且兼容原生HTTP模块的获取方式
1 | const express = require('express'); |
获取路由参数
路由参数指的是URL路径中的参数(数据)
1 | app.get('/:id/html',(req, resp)=>{ |
四、express响应设置
express框架封装了一些API来方便给客户端响应数据,并且兼容原生HTTP模块的获取方式
1 | const express = require('express'); |
五、express中间件
什么是中间件
中间件(Middleware)本质是一个回调函数
中间件函数可以像路由回调一样访问请求对象(request)、响应对象(response)
中间件的作用
中间件的作用就是使用函数封装公共操作,简化代码
中间件的类型
- 全局中间件
- 路由中间件
定义全局中间件
每一个请求到达服务端之后都会执行全局中间件函数
声明中间件函数
1 | // 声明中间件函数 |
应用中间件
1 | app.use(recordMiddleWare); |
多个全局中间件
express允许使用app.use()定义多个全局中间件
1 | app.use(function(req, resp, next)=>{ |
定义路由中间件
如果只需要对某一些路由进行功能封装,则需要路由中间件
1 | app.get('/路径', `中间件函数名`, (req, resp)=>{ |
静态资源中间件
express内置处理静态资源的中间件
1 | // 引入express框架 |
注意事项:
- index.html文件为默认打开的资源
- 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
- 路由响应动态资源,静态资源中间件响应静态资源
获取请求体数据body-parser
使用express内置的body来获取请求体
1 | const express = require('express'); |
六、Router
什么是Router
express中的Router是一个完整的中间件和路由系统,可以看做是一个小型的app对象
Router作用
对路由进行模块化,将路由单独提取出来一个文件,更好的管理路由
Router的使用
创建独立的JS文件(homeRouter.js)
1 | // 1.导入express |
主文件
1 | const express = require('express'); |
七、EJS模版引擎
什么是模版引擎
末班引擎是分离用户界面和业务数据的一种技术
什么是EJS
EJS是一个高效的JavaScript的模板引擎
EJS初体验
下载安装EJS
1 | npm i ejs --save |
代码示例
1 | // 1.引入ejs |
EJS常用语法
执行JS代码
1 | <% code %> |
输出转义的数据到模版上
1 | <%= code %> |
输出非转移的数据到模版上
1 | <%- code %> |
八、Express应用程序生成器
通过应用生成器工具express-generator可以快速创建一个应用的骨架。
可以通过npx(包含在Node.js 8.2.0及更高的版本中)命令来运行Express应用程序生成器。
1 | npx express-generator |
对于较老的Node版本,可以通过npm将Express应用程序生成器安装到全局环境中并使用。
1 | npm install -g express-generator |
-h参数可以列出所有可用的命令行参数
九、处理文件上传
首先,html文件的表单需要设置上传类型,即enctype属性。
1 | <form action="http://127.0.0.1:3000/portrait" method="post" enctype="multipart/form-data"> |
安装formidable,因为需要使用require导入,所以不能使用最新版本的,需要指定版本
1 | npm i formidable@2.1.2 |
在处理上传请求的地方
1 | router.post('/portrait', (req, resp) => { |
十、lowdb
lowdb是一个json格式的数据库文件,可以简单替代数据库进行持久化操作。
安装lowdb包:
1 | npm i lowdb@1.0.0 |
代码示例:
1 | // 导入lowdb |
但是这样的记录有一个缺点就是没有id(主键)
所以需要安装另外一个包:shortid
1 | npm i shortid |
代码示例:
1 | router.post('/account/create', (req, resp) => { |
数据展示:
1 | { |
MongoDB
一、简介
MongoDB是什么
MongoDB是一个基于分布式文件存储的数据库,官方网址:https://www.mongodb.com/
数据库是什么
数据库(database)是按照数据结构来组织、存储和管理数据的应用程序
数据库的作用
数据库的主要作用就是管理数据,对数据进行增(c)删(d)改(u)查(r)
数据库管理数据的特点
相比于纯文件管理数据,数据库管理数据有如下特点:
- 速度更快
- 扩展性更强
- 安全性更强
为什么选择MongoDB
操作语法与JavaScript类似,容易上手,学习成本低
二、核心概念
MongoDB中有三个重要概念需要掌握
- 数据库(database)数据库是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存放很多集合
- 集合(collection)集合类似于JS中的数组,在集合中可以存放很多文档
- 文档(document)文档是数据库中的最小单位,类似于JS中的对象

JSON文件示例:
1 | { |
可以通过JSON文件来理解MongoDB中的概念
- 一个
JSON文件好比是一个数据库,一个MongoDB服务下可以有N个数据库 - JSON文件中的
一级属性的数组值好比是集合 - 数组中的对象好比是
文档 - 对象中的属性有事也称为
字段
一般情况下
- 一个项目使用一个数据库
- 一个集合会存储同一种类型的数据
三、下载安装与启动
下载地址:https://www.mongodb.com/try/download/community
建议选择zip类型,通用性更强
配置步骤如下:
- 将压缩包移动到
C:\Program Files下,然后解压 - 创建
C:\data\db目录,mongdb会将数据默认保存在这个文件夹 - 以mongodb中bin目录作为工作目录,启动命令行
- 运行命令
mongod - 看到控制台最后的
waiting for connections则表明服务已经启动成功 - 然后可以使用
mongo命令连接本机的mongodb服务
注意:
- 为了方便后续方便使用mongod命令,可以将bin目录配置到环境变量Path中
千万不要选中服务端窗口的内容,选中会停止服务,可以敲回车取消选中
四、命令行交互
命令行交互一般是学习数据库的第一步,不过这些命令在后续用到较少
数据库命令
1.显示所有的数据库
1 | show dbs |
2.切换到指定的数据库,如果数据库不存在会自动创建数据库
1 | use 数据库名 |
3.显示当前所在的数据库
1 | db |
4.删除当前的数据库
1 | use 库名 |
集合命令
1.创建集合
1 | db.createCollection('集合名称') |
2.显示当前数据库中的所有集合
1 | show collections |
3.删除某个集合
1 | db.集合名.drop() |
4.重命名集合
1 | db.集合名.renameCollection('新名称') |
文档命令
1.插入文档
1 | db.集合名.insert(文档对象) |
2.查询文档
1 | db.集合名.find(查询条件) |
_id是mongodb自动生成的唯一编号,用来标识文档
3.更新文档
1 | db.集合名.update(查询条件,新的文档) |
4.删除文档
1 | db.集合名.remove(查询条件) |
五、Mongoose
介绍
Mongoose是一个对象文档模型库,官网:https://www.mongoosejs.net/
作用
方便使用代码操作mongodb数据库
使用流程
1 | const mongoose = require('mongoose'); |
字段类型
文档结构可选的常用字段类型列表
| 类型 | 描述 |
|---|---|
| String | 字符串 |
| Number | 数字 |
| Boolean | 布尔值 |
| Array | 数组,也可以用[]来表示 |
| Date | 日期 |
| Buffer | Buffer对象 |
| Mixed | 任意类型,需要使用mongoose.Schema.Types.Mixed指定 |
| ObjectId | 对象id,需要使用mongoose.Schema.Types.ObjectId指定 |
| Decimal128 | 高精度数字,需要使用mongoose.Schema.Types.Decimal128指定 |
字段值验证
Mongoose有一些内建验证器,可以对字段值进行验证
必填项
1 | title: { |
默认值
1 | author: { |
枚举值
1 | gender: { |
唯一值
1 | username: { |
unique需要重建集合才能有效果
永远不要相信用户的输入
CURD
增加
插入一条
1 | mongoose.connection.once('open', () => { |
批量插入
1 | mongoose.connection.once('open', () => { |
删除
删除一条数据
1 | BookModel.deleteOne({ _id: '6a6b3e799b87b9fa0af1e66a' }) |
批量删除
1 | BookModel.deleteMany({ author: '小红' }) |
更新
更新一条数据
1 | BookModel.updateOne({ name: '红楼梦' }, { price: 20 }) |
批量更新数据
1 | BookModel.updateMany({ name: '红楼梦' }, { price: 20 }) |
查询
查询一条数据
1 | BookModel.findOne({ name: 'CallOfDuty' }) |
批量查询数据,find方法中不传参数则表示查询所有文档
1 | BookModel.find({ author: '余华' }) |
条件控制
运算符
在mongodb中不能使用> < >= <= !==等运算符,需要使用替代符号
>使用$gt<使用$lt>=使用$gte<=使用$lte!==使用$ne
1 | // 查找id号比3大的所有记录 |
逻辑运算
$or逻辑或的情况
1 | db.students.find({$or:[{age:18},{age:24}]}); |
$and逻辑与的情况
1 | db.students.find({$and:[{age:{$lt:20}},{age:{$gt:15}}]}); |
正则匹配
挑拣中可以直接使用JS的正则语法,通过正则可以进行模糊查询
1 | db.students.find({name:/imissyou/}); |
个性化读取
字段筛选
1 | // 0:不要的字段 |
数据排序
1 | // sort排序 |
数据截取
1 | // skip跳过 limit限定 |
数据库模块化提取
目录结构:

其中config文件夹中配置连接数据库的配置
1 | module.exports = { |
db文件夹下的db.js负责连接数据库等操作
1 | module.exports = function (success, error) { |
models文件夹下负责定义文档对象
1 | const mongoose = require('mongoose'); |
index.js中为入口脚本
1 | const db = require('./db/db'); |
接口
一、简介
接口是什么
接口是前后端通信的桥梁
简单理解:一个接口就是服务中的一个路由规则,根据请求响应结果
接口的英文单词是API(Application Program Interface),所以有时也称为API接口
这里的接口指的是数据接口,与编程语言的interface不同
接口的作用
实现前后端通信
接口的开发与调用
大多数接口都是由后端工程师开发的,开发语言不限
一般情况下接口都是由前端工程师调用的,但有时后端工程师也会调用接口,比如短信接口、支付接口等
接口的组成
一个接口一般由如下几个部分组成
- 请求方法
- 接口地址(URL)
- 请求参数
- 响应结果
二、RESTful API
RESTful API是一种特殊风格的接口们主要特点有如下几个:
- URL中的路径表示
资源,路径中不能有动词,例如create,delete,update等 - 操作资源要与
HTTP请求方法对应 - 操作结果要与
HTTP响应状态码对应
规则示例:
| 操作 | 请求类型 | URL | 返回 |
|---|---|---|---|
| 新增歌曲 | POST | /song | 返回新生成的歌曲信息 |
| 删除歌曲 | DELETE | /song/10 | 返回一个空文档 |
| 修改歌曲 | PUT | /song/10 | 返回更新后的歌曲信息 |
| 修改歌曲 | PATCH | /song/10 | 返回更新后的歌曲信息 |
| 获取所有歌曲 | GET | /song | 返回歌曲列表数组 |
| 获取单个歌曲 | GET | /song/10 | 返回单个歌曲信息 |
三、json-server
json-server是一个JS编写的工具包,可以快速搭建RESTful API服务
官方网址:http://github.com/typicode/json-server
操作步骤:
1.全局安装json-server
1 | npm i -g json-server |
2.创建JSON文件(json.db),编写基本结构
1 | { |
3.以JSON文件所在文件夹作为工作目录,执行如下命令
1 | json-server --watch db.json |
默认监听端口为3000
四、接口测试工具
Apifox
使用教程


会话控制
一、介绍
所谓会话控制就是对会话进行控制
HTTP是一种无状态的协议,它没有办法区分多次的请求是否来自于同一个客户端,无法区分用户,而产品中又有大量存在的这样的需求,所以需要通过会话控制来解决该问题
常见的会话控制技术有三种
- cookie
- session
- token
二、cookie
cookie是什么
cookie是HTTP服务器发送到用户浏览器并保存在本地的一小块数据
cookie是保存在浏览器端的一小块数据
cookie是按照域名划分保存的
简单示例:
| 域名 | cookie |
|---|---|
| www.baidu.com | a=100;b=200 |
| www.bilibili.com | xid=1020;hm=1124 |
| jd.com | x=100;ocw=124 |
cookie的特点
浏览器向服务器发送请求时,会自动将当前域名下可用的cookie设置在请求头中,然后传递给服务器
这个请求头的名字也叫cookie,所以将cookie理解为一个HTTP的请求头也是可以的
cookie的运行流程
填写账号和密码校验身份,校验通过后下发cookie

有了cookie之后,后续向服务器发送请求时,就会自动携带cookie

代码操作cookie
express中可以使用cookie-parse进行处理
1 | const express = require('express'); |
不同浏览器中的cookie是相互独立的,不共享
三、session
session是什么
session是保存在服务器端的一块数据,保存当前访问用户的相关信息
session的作用
实现会话控制,可以识别用户的身份,快速获取当前用户的相关信息
session的运行流程
填写账号和密码校验身份,校验通过后创建session信息,然后将session_id的值通过响应头返回给浏览器

有了cookie,下次发送请求时会自动携带cookie,服务器通过cookie中的session_id的值确定用户的身份

session的代码操作
exprss中可以使用express-session对session进行操作
1 | const express = require('express'); |
四、session和cokkie的区别
cookie和session的区别主要有如下几点
- 存在的位置
- cookie:浏览器端
- session:服务端
- 安全性
- cookie是以明文的方式存放在客户端的,安全性相对较低
- session存放于服务器中,所以安全性相对较好
- 网络传输量
- cookie设置内容过多会增大报文体积,影响传输效率
- session数据存储在服务器,只是通过cookie传递id,所以不影响效率
- 存储限制
- 浏览器限制单个cookie保存的数据不能超过
4k,且单个域名下的存储数量也有限制 - session数据存储在服务器中,所以没有这些限制
- 浏览器限制单个cookie保存的数据不能超过
五、token
token是什么
token是服务端生成并返回给HTTP客户端的一串加密字符串,token中保存着用户信息
token的作用
实现会话控制,可以识别用户的身份,主要用于移动端APP
token的工作流程
填写账号和密码校验身份,校验通过后响应token,token一般是在响应体中返回给客户端的

后续发送请求时,需要手动将token添加在请求报文中,一般是放在请求头中

token的特点
- 服务端压力更小
- 数据存储在客户端
- 相对更安全
- 数据加密
- 可以避免CSRF(跨站请求伪造)
- 扩展性更强
- 服务间可以共享
- 增加服务节点更简单
JWT
JWT(JSON Web Token)是目前最流行的跨域认证解决方案,可用于基于token的身份验证
JWT使token的生成与校验更规范
可以使用jsonwebtoken包来操作token
1 | // 导入jsonwebtoken |
六、附录
本地域名
所谓本地域名就是只能在本机使用的域名,一般在开发阶段使用
操作流程
编辑文件C:\Windows\System32\drivers\etc\hosts
1 | 127.0.0.1 www.baidu.com |
如果修改失败,可以修改该文件的权限
原理
在地址栏输入域名之后,浏览器会先进行DNS(Domain Name System)查询,获取该域名对应的IP地址
请求会发送到DNS服务器,可以根据域名返回IP地址
可以通过ipconfig/all查看本机的DNS服务器
hosts文件也可以设置域名与IP的映射关系,在发送请求前,可以通过该文件获取域名的IP地址

