Node.js 笔记
1. 初识node.js与内置模块
1.1 回顾与思考
浏览器中的javaScript的组成部分
- JS核心语法- webAPI
为什么JavaScript可以再浏览器中被执行? 待执行的JS代码 JS解析引擎 不同的浏览器使用不同的JS解析引擎
为什么JS可以操作DOM还有BOM? 每个浏览器中内置了DOM,BOM这样的API函数,因此浏览器中的javaScript才可以调用它们
浏览器中JS的运行环境 运行环境是指代码正常运行所需要的必要环境 Chrome浏览器运行环境: V8引擎和内置API函数
- v8引擎负责解析和执行js代码- 内置API是由运行环境提供的特殊接口,只能在所属的运行环境中被调用 ** js能否做后端开发?**
1.2 Node.js简介
1.什么是Node.js? Node.js是一个基于Chrome V8引擎的JS运行环境
2.Node.js中的JS运行环境 V8引擎和内置API函数
- 浏览器是JS的前端运行环境- Node.js是Js的后端运行环境- Node.js中无法调用DOM和BOM等浏览器内置API
3. Node.js可以做什么?
4. Node.js学习路径 JS基础语法- Node.js内置API模块(fs,path,http)-第三方API模块(express,mysql)
1.3Node.js环境的安装
什么是终端? 终端是专门为开发人员设计的,用于实现人机交互的一种方式 1.windows+R 2.输入cmd
1.4在Node.js环境中执行JS代码
1.打开终端 直接在地址栏敲cmd,可以使cmd切换到当下文件的地址 还可以在当前目录下的空白处按住shift键,右键打开powerShell
2.输入node 要执行的js文件的路径 node 空格 文件名
终端中的快捷键

2.fs文件系统模块
2.1什么是文件系统模块
fs模块是Node.js官方提供的、用来操作文件的模块,它提供了一系列的方法和属性,用来满足用户对文件的操作需求
2.2读取指定文件中的内容
fs.readFile()的语法格式 使用fs.readFile()方法,可以读取指定文件中的内容,语法格式如下:
1 | fs.readFile(path[,options],callback) |
- 参数1:必选参数,字符串,表示文件的路径- 参数
- 2:可选参数,表示以什么编码格式来读取文件- 参数
- 3:必选参数,文件读取完成后,通过回调函数拿到读取的结果。
1 | // 1.导入fs模块,来操作文件 |
判断文件是否读取成功
1 | // 1.导入fs模块,来操作文件 |
2.3向指定的文件中写入内容
fs.writeFile()的语法格式 使用该方法,可以向指定的文件中写入内容,语法格式如下
1 | fs.writeFile(file, data[, options], callback) |
- 参数1:必选参数,字符串,表示文件的存放路径- 参数
- 2:必选参数,表示要写入的内容- 参数
- 3:可选参数,表示以什么编码格式来读取文件,默认值是utf8- 参数
- 4:必选参数,文件写入完成后的回调函数。
判断文件是否读取成功
案例:考试成绩整理
核心实现步骤
- 导入需要的fs文件系统模块
- 使用fs.readFile()方法,读取素材目录下的成绩.txt文件
- 判断文件是否读取失败
- 文件读取成功后,处理成绩数据
- 将处理完成的成绩数据,调用fs.writeFile()方法,写入到新文件中

1 | // 导入fs模块 |
2.4路径问题

3 path路径模块
path模块是Node.js官方提供的,用来处理路径的模块,它提供一系列的方法和属性,用来满足用户对于路径的处理需求 如果要在JS代码中,使用path模块来处理路径,则需要使用以下的方式先导入它
1 | const path=require('path') |
3.1 path.join()语法格式
使用path.join方法,可以把多个路径片段拼接为较为完整的路径字符串
1 | path.join([...paths]) |
注意:今后凡是涉及路径拼接的操作,都是使用path.join()方法进行处理,不要直接使用+进行字符串的拼接
3.2 path.basename()
使用该方法可以获取路径中的最后一部分,经常通过这个方法获取路径中的文件名,语法格式如下
1 | path.basename(path[,ext]) |
参数:path:必选参数,表示一个路径的字符串 ext可选参数,表示文件拓展名 返回:表示路径中的最后一部分
3.3 path.extname()
使用该方法可以获取路径中的拓展名部分,语法格式如下
1 | path.extname(path) |
path:必选参数,表示一个路径的字符串 返回:返回得到的拓展名字符串
案例:时钟
1 | // 1.1 导入需要的模块并创建正则表达式 |
注意 1.fs.write()方法只能用来创建文件,不能用来创建路径 2.重复调用fs.writeFile()只能写入同一个文件,新写入的内容会覆盖之前的旧内容
4.http模块
4.1 基础概念
什么是客户端,什么是服务器? 在网络节点中,负责消费资源的电脑,叫做客户端。 负责对外提供网络资源的电脑,叫做服务器。 Http模块是Node.js官方提供的,用来创建web服务器的模块。通过http模块提供的Http.createServer()方法,就能方便的把一台普通电脑,变成一台web服务器,从而对外提供Web资源服务。
1 | const http=require('http') |




4.2 创建最基本的web服务器
1.导入Http模块
1 | const http=require('http') |
2.创建web服务器实例
1 | const server=http.createServer() |
3.为服务器实例绑定request事件,监听客户端的请求
1 | //使用服务器实例的.on()方法,为服务器绑定一个request事件 |
4.启动服务器
1 | //调用server.listen(端口号,cb回调)方法,即可启动web服务器 |
4.3 req请求对象
只要服务器接收到了客户端的请求,就会调用server.on()为服务器绑定的request事件处理函数 如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下的方式:
1 | server.on('request',(req,res)=>{<!-- --> |
4.4 res响应对象
1 | server.on('request',(req,res)=>{<!-- --> |
4.5解决中文乱码问题
当调用res.end()方法,向客户端发送中文内容的时候,会出现乱码问题,此时,需要手动设置内容的编码格式
1 | server.on('request',(req,res)=>{<!-- --> |
4.6根据不同的url响应不同的html内容
1 | server.on('request',function(req,res){<!-- --> |
5.模块化
5.1 模块化的基本概念
什么是模块化? 模块化是指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程。对于整个系统来说,模块是可组合、分解和变换的单元 编程领域中的模块化:就是遵守固定的规则,把一个大文件拆成独立并且互相依赖的多个小模块。
模块化规范 就是对代码进行模块化的拆分与组合时,需要遵守的规则 使用什么样的语法格式来引用模块 在模块中使用什么样的语法格式向外暴露成员
5.2Node.js中的模块化
根据模块来源的不同,将模块分为了三大类,分别是: 内置模块(fs,path,http) 自定义模块(用户创建的每个Js文件)
第三方模块(由第三方开发出来的模块)
什么是模块作用域? 和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域 防止了全局变量污染的问题
向外共享模块作用域中的成员 module对象:在每个·.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息 module.export对象 可以使用该对象将模块内的成员共享出去,供外界使用。外界用require方法导入自定义模块时,得到的就是Module.exports所指的对象

exports对象 由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象。默认情况下,exports和module.exports指向同一个对象,最终共享的结果,还是以module.exports指向的结果为准
exports和module.exports的使用误区
模块化规范
5.3 npm与包
包的基本概念
Node.js中的第三方模块又叫做包 从哪里搜索包: 从哪里下载包: 如何下载包?npm包管理工具
格式化时间的高级做法
1.使用npm包管理工具,在项目中安装格式化时间的包moment
2.使用require()导入格式化时间的包
3.参考Moment的官方API文档对时间进行格式化
1 | //1.导入Moment包,注意导入的名称,就是装包时候的名称 |
在项目中安装包的命令
1 | npm install 包的完整名称 |
简写形式
1 | npm i 包的完整名称 |
注意点
1.初次装包完成后,在项目文件夹下多一个叫做node_modules的文件夹和package-lock.json的配置文件,其中node_modules文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包 package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的版本号,下载地址等
2.安装指定版本的包: 默认情况下,会自定安装最新版本的包,如果需要安装指定版本的包,可以在包名之后,通过@符号指定具体的版本
1 | npm i moment@2.22.2 |
3.包的语义化版本规范 包的版本号是以“点分十进制”形式进行定义的,总共有三位数字,例如2.24.0 其中每一位数字所代表的含义如下:第一位:大版本 第二位:功能版本 第三位:bug修复版本 只要前面的版本号增长了,则后面的版本号归零
包管理配置文件
1.多人协作的问题:第三方的包的体积过大,不方便成员之间共享项目源代码 解决方案:共享时剔除node_modules
2.在项目根目录中,创建一个叫做package.json的配置文件,即可用来记录在项目中安装了哪些包,从而方便剔除node_modules目录之后,在团队成员之间共享项目的源代码 今后在项目开发中,一定要把Node_modules文件夹,添加到.gitignore忽略文件夹中
3.npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理配置文件:
1 | npm init -y |
上述命令只能在英文的目录下运行成功!所以项目文件夹的名称一定要使用英文命名,不能出现空格。运行npm install命令安装包的时候,npm包管理工具,会自动把包的名称和版本号,记录到package.json中
4.一次性安装所有包 可以运行npm install命令,一次性安装所有安装所有的依赖包
1 | //执行npm install 命令时,npm 包管理工具会先读取package.json中的dependencies节点 |
5.卸载包 可以npm uninstall
1 | //使用npm uninstall 具体的包名 来卸载包 |
注意 npm uninstall命令执行成功后,会把卸载的包,自动从package.json的dependencies中移除掉

解决下包速度慢的问题
淘宝NPM镜像服务器 镜像:是一种文件存储形式每一个磁盘上的数据在另一个磁盘上存在完全相同的副本即为镜像 切换npm的下包镜像源。下包的镜像源,指的就是下包的服务器地址
1 | npm config get registry |
nrm 为了更方便的切换下包镜像源,我们可以安装nrm这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源
1 | //通过npm包管理工具,将nrm安装为全局可用的工具 |
包的分类
项目包:那些被安装到项目的node_modules目录中的包,都是项目包 项目包又分为两类,分别是开发依赖包和核心依赖包
1 | npm i 包名-D //开发依赖包(会被记录到devDependencies节点下) |
1.全局包
1 | npm i包名-g //全局安装指定的包 |
注意:只要工具性质的包,才有全局安装的必要性,因为它们提供了很好的终端命令 判断某个包是否需要全局安装后才能使用,可以参考官方提供的使用说明即可
2.i5ting_toc i5ting_toc是一个可以把md文档转为Html页面的小工具,使用步骤如下
1 | //将i5ting_toc安装为全局包 |
3.规范的包结构

开发属于自己的包
1.需要实现的功能 格式化日期 转义Html中的特殊字符 还原html中的特殊字符
5.4 模块的加载机制
优先从缓存中加载 模块在第一次被加载后会被缓存。这也意味着多次调用require()不会导致模块的代码被多次执行。注意:不论是内置模块,自定义模块,还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
内置模块的加载机制 内置模块加载优先级最高。
自定义模块的加载机制 使用require()加载自定义模块时,必须指定以./或…/开头的路径标识符。在加载自定义模块时,如果没有指定的话,则node模块就会把他当成内置模块或者第三方模块进行加载 同时,在使用require()导入自定义模块时,如果省略了文件的拓展名,则node.js就会按顺序分别尝试加载以下的文件
1.按照确切的文件名进行加载
2.补全.js拓展名进行加载
3.补全.json拓展名进行加载
4.补全.node拓展名进行加载
5.加载失败,终端报错
第三方模块的加载机制 如果传递给require()的模块标识符不是一个内置模块,也没有./等等开题,则Node.js会从当前模块的父目录开始,尝试从.node_modules文件夹中加载第三方模块。如果没有找到第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录
目录作为模块
6.express
6.1express简介
Express是基于Node.js平台,快速,开放,极简的Web开发框架 思考:不使用Express能否创建Web服务器? 能,使用Node.js提供原生的http模块即可 但是http内置模块用起来很复杂,Express是基于内置的http模块进一步封装起来的,能够极大的提高开发效率

express的安装 在项目所处的目录中,运行如下的终端命令,即可将express安装到项目中使用:
1 | npm i express@4.17.1 |
使用express创建最基本的服务器
1 | //1.导入express |
6.2 Express的基本使用
监听GET请求
通过app.get()方法,可以监听客户端的GET请求,具体的语法格式如下:
1 | //参数1:客户端请求的url地址 |
监听POST请求
通过app.post()方法,可以监听客户端的POST请求,具体的语法格式如下:
1 | //参数1:客户端请求的url地址 |
把内容响应给客户端
通过res.send()方法,可以把处理好的内容,发送给客户端
1 | app.get('/user',(req,res)=>{<!-- --> |
获取URL中携带的查询参数
通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数:
1 | app.get('/', (req, res) => {<!-- --> |
获取URL的动态参数
通过req.params对象,可以访问到Url中,通过:匹配到的动态参数
1 | //url地址中,我们开业通过:参数名的形式,匹配动态参数值 |
汇总
1 | //1.导入express |
6.3 托管静态资源



6.4 nodemon
当基于Node.js编写了一个网站应用的时候,传统的方式,是运行node.app.js命令,来启动项目。
这样做的坏处是:当代码被修改之后,需要手动重启项目。
现在,我们可以node命令替换为nodemon命令,使用nodemon app.js来启动项目,
这样做的好处是:代码被修改之后,会被nodemon监听到,从而实现自动重启项目的效果
1 | node app.js |
7.express 路由
7.1 路由的概念
广义上来讲,路由就是映射关系 在Express中,路由指的是客户端请求与服务器处理函数之间的映射关系 Express中的路由分三部分组成,分别是请求的类型,请求的URL地址,处理函数。格式如下:
1 | app.METHOD(PATH,HANDLER) |
express中路由的例子
1 | //匹配GET请求,且请求URL为/ |
路由的匹配过程
路由的使用 在express中使用路由最简单的方式,就是把路由器挂载到APP上,示例代码如下
1 | const express=require('express') |
7.2 路由的使用
模块化路由:为了方便对路由进行模块化的管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。将路由抽离为单独模块的步骤如下:
1.创建路由模块对应的.js文件
2.调用express.Router()函数创建路由对象
3.向路由对象挂载具体的路由
4.使用module.exports向外共享路由对象
5.使用app.use()函数注册路由模块
创建路由模块
1 | // 这是路由模块 |
注册路由模块
1 | // 1. 导入路由模块 |
为路由模块添加前缀
1 | // 1. 导入路由模块 |
全部代码
1 | const express = require('express') |
8 express中间件
8.1 Express中间件的概念



8.2 中间件的初体验
定义中间件函数
1 | //常量mv所指向的,就是一个中间价函数 |
全局生效的中间件函数
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间价。通过调用app.use(中间件函数),即可定义一个全局生效的中间价,示例代码如下:
1 | //全局生效的中间件 |
定义全局中间件的简化形式
1 | // 这是定义全局中间件的简化形式 |
全部代码
1 | const express = require('express') |
中间件的作用

1 | const express = require('express') |
定义多个全局中间件
可以使用app.use()连续定义多个全局中间件,客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用,示例代码如下
1 | const express = require('express') |
局部生效的中间件
不使用app.use()定义的中间件,叫做局部生效的中间件
1 | // 导入 express 模块 |
定义多个局部中间件
可以在路由中,通过如下两种等价的方式,使用多个局部中间件
1 | // 导入 express 模块 |
了解中间件的注意事项

8.3 中间件的分类




1 | // 导入 express 模块 |
错误级别的中间件,放到所有路由之后

1 | // 导入 express 模块 |

1 | // 导入 express 模块 |
8.4 自定义中间件

定义中间件
使用app.use()来定义全局生效的中间件,代码如下
1 | app.use((req, res, next) => {<!-- --> |
监听req的data事件

监听req的end事件

使用querystring模块解析请求体数据

将解析出来的数据对象挂载为req.body
完整代码
1 | // 导入 express 模块 |
将自定义中间件封装为模块

1 | // 导入 express 模块 |
9.使用express写接口
9.1 创建基本的服务器
1 | // 导入 express |
9.2 创建API路由模块

9.3编写GET接口

9.4 编写Post接口

9.5CORS跨域
接口的跨域问题:刚才编写的GET和POST请求,存在一个很严重的问题:不支持跨域请求。
解决接口跨域问题的方案主要有两种:
1.CORS(主流的方案,推荐使用)
2.JSONP(有缺陷的解决方案:只支持GET请求) 使用cors中间件解决跨域问题
CORS请求的分类 客户端在请求CORS接口时,根据请求方式和请求头的不同,可以将CORS的请求分为两大类,分别是:
1.简单请求
2.预检请求
9.6 JSONP接口




