1. Node.js时基于Chrome V8 引擎的JavaScript运行环境。官网:Node.jsNode.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.https://nodejs.org/en/
2. Node.js中的Javascript的运行环境
注意:1.浏览器时javascript的前端运行环境
2.Node.js是JavaScript的后端运行环境
3.Node.js中无法调用DOM和BOM等浏览器内置API
3.Node.js可以做什么
Node.js 作为一个javascript的运行环境,仅仅提供了基础的功能和API。
1)基于Express框架的Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网,可以快速构建web应用
2)基于Electrom框架 Electron | Build cross-platform desktop apps with JavaScript, HTML, and CSS.
3)基于 restify框架 Restify ,可以快速构建API接口项目
4)读写和操作数据库,创建使用的命令行工具辅助前端开发 、etc..
4.Node.js 怎么学
Node.js 学习路径
javascript基础语法+Node.js 内置API模块(fs,path,http等)+第三方API模块(express,mysql等)
5. Node.js安装 1)官网下载安装包 https://nodejs.org/en/ LTS(建议安装)为长期稳定版 CURRENT为尝鲜版本
2)建议安装在默认路径,(C盘)
3) 命令行 输入 node -v 查看node版本号
6.什么是终端: 终端(terminal)是专门为开发人员设计的,用于实现人机交互的一种方式。
作为一名合格的程序员,我们有必要认识和脊柱一些常用的终端命令,来辅助我们更好的操作与使用计算机。
7. 在Node.js 环境中执行JavaScript代码
1)打开终端
2)输入node 要执行的js文件的路径 (要切换到文件所处的目录当中)
3)在文件 所处位置 按住shift + 右键 打开powershell
8.fs模块是Node.js官方提供的、用来操作文件的模块。他提供了一系列的方法和属性,用来满足用户对文件的操作需求
例如:
fs.readFile()方法,同来读取指定的文件中的内容
fs.writefile()方法,用来向指定的文件中写入内容
如果要在JavaScript代码中,使用fs模块来操作文件,则需要使用如下的方式先导入它:
const fs = require('fs')
9. fs.readfile()语法格式
fs.readFile(path[,options], callback)
path, callback可选参数 options
path:必选参数,字符串,表示文件的路径
options:可选参数,表示以什么编码格式来读取
callback:必选参数,文件读取完成后,通过回调函数拿到读取的结果
例如:
//2. 带哦用fs.readFiles()方法读取文件
//参数1:读取文件存放路径
//参数2:读取文件时候采用的编码格式,一般默认指定 utf8
fs.readFile("./files/11.txt", "utf8", function (err, dataStr) {
//2.1打印失败的结果
//如果读取成功 则err的值为null
//如果读取失败 则err的值为错误对象 dataStr的值为 undefined
console.log(err);
console.log("------------");
//2.2打印成功的结果
console.log(dataStr);
});
10.判断文件是否读取成功
例如:
const fs = require("fs");
fs.readFile("./files/11.txt", "utf8", function (err, dataStr) {
if (err) {
return console.log("文件读取失败" + err.message);
}
console.log("读取文件成功" + dataStr);
});
11. 向指定文件中写入内容
使用fs.writeFile()方法,可以向指定的文件中写入内容,语法格式如下:
fs.writeFile(file,data[,options], callback)
参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径。
参数2:必选参数,表示要写入的北荣。
参数3:可选参数,表示以什么格式写入内容,默认值是utf8
参数4:必选参数,文件写入完成后的回调函数
const fs = require('fs')
fs.writeFile('./files/2.txt', 'hello Node.js!' , function(err) {
console.log(err)
})
12. 判断文件是否写入成功
const fs = require("fs");
fs.writeFile("F:/files/2.txt", "hello node.js", function (err) {
if (err) {
return console.log("文件写入失败" + err.message);
}
console.log('文件写入成功')
});
13. 整理成绩案例 (见文件包)
14.路径拼接出错误问题
在使用fs模块操作文件时,如果提供的操作路径是以./ 或../的相对路径时,很容易出现路径动态拼接错误的问题。
原因:代码在运行时,会以执行node命令时所处的目录,动态拼接储备操作文件的完整路径。
const fs = require("fs");
fs.readFile("./files/1.txt", "utf8", function (err, dataStr) {
if (err) {
return console.log("读取文件失败" + err.message);
}
console.log("scucess" + dataStr);
});
15.提供一个完整的绝对路径(复制完路径后,加一个\) 缺点:移植性差,不利于维护
16. 加__dirname
fs.readFile(__dirname + "/files/1.txt", "utf8", function (err, dataStr) {
if (err) {
return console.log("读取文件失败" + err.message);
}
console.log("scucess" + dataStr);
});
17.path 模块时node.js官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。
path.join()方法,同来将多个路径偏暖拼接成一个完整的路径字符串
path.basename()方法,用来从路径字符串中,将文件名解析出来
const path = require('path')
18.路径拼接
path.join()的语法格式
path.join([..path])
..path
返回值
今后凡是涉及到路径拼接的操作,都要用path.join()方法进行处理。不要直接用+ 进行字符串拼接
19.
1)获取路径中的文件名
path.basename()的语法格式
使用path.basename()方法,可以获取路径中的最后一个部分,经常通过这个方法获取路径中的文件名,语法格式如下:
path.basename(path[, ext])
path
ext
返回值:
获取文件名 1. 有扩展名 2. 没有扩展名
2).获取文件扩展名
path.extname()
20.时钟案例 (见文件)
注意点1.fs.writeFile()只能用于创建文件,不能用于创建路径
2.重复调用fs.writeFile()写入同一文件,新写入的内容会覆盖之前的内容
21.什么是http模块
在网络节点中,负责消费资源的电脑,叫做客户端;负责对外提供网络资源的电脑叫客户端
http 模块时Node.js官方提供的、用来创建web服务器的模块。通过http模块提供的http.createServer()方法,就能方便的八姨太普通的电脑,变成一台web服务器,从而提供web资源服务。
22.http模块的作用
服务器和普通电脑的区别,服务器上安装了web服务器软件,例如:IIS,Apache等。通过安装这些服务器软件,就能把一台普通的电脑变成一台web服务器。
在Node.js中,我们不需要使用IIS、Apache等这些第三方的软件。因为我们可以基于Node.js提供的http模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供web服务。
23.服务器相关概念
1).IP地址就是互联网上每台计算机的唯一地址,因此IP地址具有唯一性。如果把“个人电脑”比作“一台电话”,那么"IP地址”就相当于“电话号码”, 只有在知道对方IP地址的前提下,才能与对印度个电脑之间进行数据通信。
2).域名和域名服务器
尽管IP地址能够唯一地标记网络上的计算机,但IP地址是一长串数字,不直观,而且不便于记忆,于是人们又发明了另一套字符型的地址方案,即所谓的域名(Domain Name)地址。
IP和域名时一一对应的关系。这份对应关系存放在一种叫做域名服务器的电脑中。
3). 端口号
计算机中的端口号,就好像是现实生活中的门牌号一样。通过门牌号,外卖小哥可以在整栋大楼众多房间中,准备把外卖送到你的手中。
同样的道理,在一台电脑中,可以运行成百上千个web服务器。每隔web服务器都对应一个唯一的端口号。客户端发送过来的网络请求,通过端口号,可以准确的交给对应的web服务进行处理。
注意点
1.每个端口号不能同时被多个web服务占用。
2.在实际应用中,URL中的80端口可以被省略。
24.创建最基本的web服务器
1.创建web服务器的基本步骤
1). 导入http模块
const http = require('http')
2).创建web服务器实例
调用http.createServer()方法,既可以快速创建一个web服务器实例
const server = http.createServer()
3).为服务器绑定request事件,监听客户端的请求
4).启动服务器
调用服务器实例的 .listen()方法,既可以启动当前的web服务器实例
25. req请求对象
只要服务器接收到了客户端的请求,就会通过调用server.on()为服务器绑定的request事件处理函数。
如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下的方式:
26. res响应对象
通过res.end向客户端发送指定内容
27. 解决中文乱码问题
28.个面具不同url 相应不同的html内容
1). 获取请求的url地址
2). 设置默认的响应内容
3). 判断用户请求的是否为/ 或index.html首页
4).判断用户请求的是否为/about.html 关于页面
5). 设置Content-Type 响应头,防止中文乱码
6). 使用res.end()把内容响应给客户端
29.时钟web服务器案例
1.核心思路如下:
2.实现步骤
1). 导入需要的模块
2).创建基本的web服务器
3).将资源的请求url地址映射为文件的从存放路径
4).读取文件内容并相应给客户端
5).优化资源的请求路a径
30. 模块化的概念
1)编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并且互相依赖的多个小模块
把代码进行模块化拆分的好处
1、提高代码的复用性
2、提高了代码的可维护性
3、可以实现按需加载
2)模块化规范
模块化规范就是对大妈进行模块化拆分与组合时,需要遵守的那些规则。
例如:
使用什么样的语法来引用模块
在模块中使用什么样的语法格式向外暴露成员
模块化规范的好处:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的互相调用,利人利己。
31.Node.js中模块的分类
Node.js中根据模块来源不同,将模块分为了三大类,分别是:
1).内置模块:是由Node.js官方提供的,例如fs,path,http等
2).自定义模块: 用户创建的每一个.js文件,都是自定义模块
3).第三方模块:由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载
32.加载模块
注意:当使用require()方法加载其他模块时, 会执行被加载抹开中的代码
33. 什么是模块作用域
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。
模块作用域的的好处,防止了全局变量污染的问题
34.向外共享模块作用域中的成员
1.module对象
在每一个 .js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息,打印如下:
35.modeule.exports对象
在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,共外界使用。
外界用require()方法导入自定义模块时,得到的就是module.exports所指向的对象。
36.共享成员时的注意点
使用require()方法导入模块时, 导入结果,永远以module.exports只想的对象为准。
37. 由于module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象。 默认情况下,exports和module.exports只想同一个对象。 最终共享的结果,还是以module.exports只想的对象为准。
38. exports 和 module.exports的使用误区
时刻谨记, require() 模块时,得到的永远时module.exports只想的对象
39.Node.js中的模块化规范
Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特征和个模块之间的互相依赖。
CommonJS规定
1). 每个模块内部,module变量代表当前模块
2). module 变量是一个对象,它的exports属性(即module.exports)是对外的接口
3). 加载某个模块,其实时加载该模块的module.exports属性。require()方法用于加载模块
40.包与npm-包的概念
1).什么是包
Node.js 中的第三方模块又叫做包。
第三方模块和包值得时同一个概念,只不过叫法不同。
2).包的来源
不同于Node.js中的内置模块与自定义模块,包是由第三方个人或团队开发出来的,免费供所有人使用。
注意:Node.js中的包都是免费且开源的,不需要付费即可免费下载使用
3). 为什么需要包
由于Node.js的内置模块仅提供了一些底层的API,导致在基于内置模块进行项目开发时,效率很低。
包是基于内置模块封装出来的,提供了更高级、更方便的API,极大的提高了开发效率
包和内置模块之间的关系,类似于jQuery和浏览器内置API之间的关系。
4).从哪里下载包
国外有一家IT公司,叫做npm,Inc.这家公司旗下有一个非常著名的网站:http://www.npmjs.com/
,他是全球最大的包共享平台,你可以从这个网站上搜索任何你需要的包,只要你有足够的耐心。
到目前为止,全球约有1100多万的开发人员,通过这个包共享平台,开发并共享了120多万个包供我们使用。
npm,Inc.这家公司提供了一个地址为https://registry.npmjs.org/的服务器,来对外共享所有的包,我们可以通过这个服务器山刚下载自己所需要的包。
5). 如何下载包
npm,Inc.这家公司提供了一个包管理工具,我们可以使用这个包管理工具,从https://registry.npmjs.org/服务器把需要的包下载到本地使用。
这个包管理工具的名字叫做 Node Package Manager (简称npm 包管理工具), 这个包管理工具随着Node.js的安装包一起被安装到了用户的电脑上。
41.npm初体验
1). 格式化时间的传统做法 见文件js的15、16
2). 格式化时间的高级做法 1.使用npm包管理工具,在项目中 安装格式化时间的包 moment
2.使用require()导入格式化时间的包
3.参考 moment的官方API文档对事件进行格式化
42.在项目中安装包的命令
如果想在项目中安装指定名称的包,需要运行如下的命令:
npm install 包的完整名称(简写 npm i)
43. 初次装包后多了哪些文件
初次装包完成后, 在项目文件夹下多一个叫做node_module的文件夹和package-lock.json的配置文件。
其中:
node_modules 文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包。
package-lock.json 配置文件用来记录node_module 目录下每一个包的下载信息,例如包的名字、本版号、下载地址等。
注意:程序员不要修改node_modules 或package-lock.json文件中的任何代码,npm包管理工具会自动维护它们
44. 安装指定版本的包
默认情况下,使用npm install命令安装包的时候,会自动安装最新版本的包。如果需要安装指定版本的包,可以在包名之后,通过@符号指定具体的版本,例如:
npm i [email protected]
45. 包的语义化版本规范
包的版本号是以“点分十进制” 形式进行定义的,总共有三位数字。例如2.24.0
其中每一位数字所代表的含义如下:
第1位数字:大版本
第2位数字:功能版本
第3位数字:Bug修复版本
版本号提升的规则:只要前面的版本号增长了,则后面的版本号归零
46.包管理配置文件
npm规定,在项目中,必须提供一个叫做package.json的包管理配置文件。用来记录与项目有关的一些配置信息, 例如:
项目的名称、版本号、描述等
项目中都用到了哪些包
哪些包只在开发期间会用到
哪些包只在开发和部署时都需要用到
47. 多人协作的问题
第三方包的体积过大, 不方便团队成员共享项目的源代码
48. 如何记录项目中都用了哪些包
在项目根目录中,创建一个叫做package.json的配置文件, 既可用来记录项目中安装了哪些包。 从而方便剔除node_modules 目录之后, 在团队成员之间共享项目源代码。
注意:今后在项目开发项目中,一定要把node_modules文件夹, 添加到.gitinore文件中
49.快速创建package.json
npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理工具配置文件:
npm init -y
1.上述命令只能在英文的目录下成功运行! 所以,项目文件夹的名称一定要使用英文命名,不要使用中文, 不能出现空格
2.运行 npm install 命令安装包的时候, npm包管理工具会自动把包的名称和版本号,记录package.json中
50. dependencies节点
package.json文件夹中, 有一个dependencies节点, 专门用来记录您使用npm install命令安装额哪些包
51. 一次性的安装所有的包
可以运行npm install命令(或npm i )一次性安装所有的依赖包
当我们拿到一个剔除了node_modules的项目后,需要先把所有的包下载到项目中,才能将项目运行起来。
否则会报类似于下面的错误:
Error: Cannot find module 'moment'
52.卸载包
可以运行 npm uninstall命令, 来卸载指定的包:
53.devDependencies节点
如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDependencies节点中。代码: npm i 包名 -D
如果某些包在开发和项目上线之后都会用到,则建议把这些包记录到dependencies节点中。
54.解决下包速度慢的问题
在使用npm下包的时候,默认从国外的http://registry.npmjs.org/服务器进行下载,此时,网络数据的传输需要经过漫长的海底光缆,因此下包速度会很慢。
55.淘宝npm镜像服务器
淘宝在国内搭建了一个服务器,专门把国外官方服务器上的包同步到国内的服务器,然后再国内提供下包的服务。从而极大的提高了下包的速度。
镜像是一种文件存储的形式,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。
56.切换npm的下包的镜像源
下包的镜像源, 指的就是下包的服务器地址
查看当前下包镜像源
npm config get registry
切换为淘宝的镜像源
npm config get registry=http://registry.npm.raobao.org/
检查镜像源是否下载成功
npm config get registry
57. nrm
为了更方便的切换下包的镜像源, 我们可以安装nrm 这个小工具, 利用nrm提供的终端命令, 可以快速查看和切换下包的镜像源
通过npm的包管理器, 将nrm安装为全局可用的工具
npm i nrm -g
查看所有可用的镜像源
nrm ls
将下包的镜像源切换为taobao 镜像
nrm use taobao
58.包的分类
使用npm包管理工具下载的包, 共分为两大类,分别是:
1).项目包: 那些被安装到项目的node_module目录中的包,都是项目包。
项目包又分为两类,分别是:
开发依赖包(被记录到devDependencies 节点中的包, 旨在开发期间会用到)
核心依赖包 (被记录到dependencies 节点中的包, 在开发期间和项目上线后都会用到)
2).全局包 :在执行npm install 命令时,如果提供了 -g参数, 则会把包安装为全局包。
全局包会被安装到C:\Users\用户目录\AppleData\Roaming\npm\node_modules目录下。
npm i 包名 -g 全局安装指定的包
npm uninstall 包名 -g 卸载全局安装的包
注意:
只有工具性质的包,才有全局安装的必要性。 因为它们提供了好用的终端命令
判断某个包是否需要全局安装后才能使用, 可以参考官方提供的使用说明即可
3). i5ting_toc
i5ting_toc是一个可以把md文档转为html的小工具,使用步骤如下:
将i5ting_toc 安装为全局包
npm install -g i5ting_toc
调用i5ting_toc 轻松实现md 转html的功能
i5ting_toc -f 要转换的md文件路径 -o
4). 规范的包结构
一个规范的包,它的结构组成,必须符合一下3点要求:
1).包必须以单独的目录存在
2).包的顶级目录下必须要包含package.json这个包管理配置文件
3). package.json中必须包含name, version, main 这三个属性,分别代表包的名字、版本号、包的入口。
59.开发属于自己的包
1.需要实现的功能
2.初始化包的基本结构
1).新建itheima-tools文件夹,作为包的根目录
2).在itheima-tools文件夹中,新建如下三个文件:
package.json
index.js
README.md
3.初始化package.json
60. 在index.js中定义格式化时间的方法
61.在index.js中定义还原HTML的方法
62.将不同功能进行模块化拆分 (见文件 itheima-tools)
1).将格式化时间的功能,拆分到 src ->dateFormat中
2).讲处理HTML字符串的功能,拆分到src->htmlEscape.js中
3).在index.js中, 导入两个模块,得到需要向外共享的方法
4).在index.js中,使用module,exports把对应的方法共享出去
63.编写包的说明文档
包的根目录中的README.md文件,时包的使用说明文档。
安装方式、导入方式、格式化时间、转移HTML中的特殊字符、还原HTML中的特殊字符、开源协议
64.发布包
1).创建npm账号
2).登录npm账号 (在终端)npm login
3).把包发布到npm上:将终端切换到包的目录之后,运行npm publish命令,即可将包发布到npm上(注意:包名不能雷同)。
4).删除一发布的包 运行 npm unpublish 包名 --force 命令,即可从npm删除已发布的包
65.模块的加载机制
1).模块在第一次加载后会被缓存。这也意味着多次调用require()不会导致 模块的代码被执行多次。
2).内置模块的加载机制
内置模块时由node.js官方提供的模块。内置模块的加载优先级最高。
例如,require('fs')始终返回内置的fs模块,既是在node_modules目录下有名字相同的包也叫fs。
3).自定义模块的加载机制
使用requrie()加载自定义模块时,必须指定以./或../的路径标识符。在加载自定义模块时,如果没有指定./或../这样的路径标识符,则node会把它当作内置模块或第三方模块进行加载。
在使用require()导入自定义模块时,如果省略了文件的扩展名,则node.js会按顺序分别尝试加载以下的文件:
1.按照确切的文件名进行加载
2.补全.js扩展名进行加载
3.补全.json扩展名进行加载
4.补全.node扩展名进行加载
4).第三方模块的加载机制
如果传递给require()的模块不是一个内置模块, 也没有以 ./ 或者../开头,则node.js会从当前模块的夫目录开始,尝试从/node_modules文件夹中加载第三方模块。
例如,假设在 'C:\Users\itheima\project\foo.js’ 文件里调用了require('tool'),则node.js会按以下顺序查找:
1).C:\Users\itheima\project\node_modules\tools
2).C:\Users\itheima\node_modules\tools
3).C:\Users\node_modules\tools
4).C:\node_modules\tools
5).目录作为模块
当把目录作为模块标识符,传递给require()进行加载时,由三种加载方式:
1).json文件里的 main 属性指向的文件
2). index
66.express简介
1). 什么是express
官方给出概念:express是基于node.js平台,快速、开放、极简的web开发框架。
通俗的理解,express的作用和node.js内置的http模块类似,都是用来创建web服务器的。
express的本质:就是一个npm里的第三方的包,提供了快速创建web服务器的快捷方法
express中文官网:http://www.expressjs.com.cn/
2).进一步理解express
思考:不适用express能否创建web服务器
答案:能,使用node.js提供的原生http模块即可
思考:既生瑜何生亮(有了http模块,为何还要用express)
答案:http内置模块用起来很复杂,开发效率低;express是基于http模块进一步封装出来的,能够极大的提高开发效率
思考:http内置模块于express是什么关系
答案:类似于web api 和 jQuery的关系。后者是基于前者进一步封装出来的。
3).express能做什么
对于前端程序员,最常见的两种服务器,分别是:
web网站服务器:专门对外提供web网页资源的服务器
api接口服务器:专门对外提供api接口的服务器
使用express,我们可以方便、快速的创建web 网站服务器或api接口的服务器
67.express的基本使用
1).安装
在项目所处的目录中,运行如下的终端命令,即可将express安装到项目中使用:
npm i [email protected]
2).创建基本的web服务器
68.express监听GET和POST请求&参数
1). 监听get请求
通过app.get()方法
//参数1: 客户段请求 URL地址
//参数2: 请求对应的处理函数
req:请求对象
res:响应对象
app.get('请求URL',function(req, res) {/*处理函数*/})
2). 监听post请求
通过app.post()方法
//参数1: 客户段请求 URL地址
//参数2: 请求对应的处理函数
req:请求对象
res:响应对象
app.post('请求URL',function(req, res) {/*处理函数*/})
3).把内容相应给客户端
通过res.send()方法
69.获取URL中携带的查询参数
通过req.query对象
70.获取URL中的动态参数
通过req.params对象,可以访问URL中,通过:匹配到的动态参数:
可以有连个动态参数
71.express静态资源处理
1). express.static()提供了一个非常好的函数,叫做express.static(),通过它,我们可以非常方便的创建一个静态资源服务器,例如,通过如下代码就可以将public目录下的图片、css文件、javascript文件开放访问了:
app.use(express.static('public'))
现在你就可以访问public目录中所有的文件了:
http://localhost:3000/images/bg.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/login.js
注意:express在指定的静态目录中查找文件,并对外提供资源的访问路径。
因此,存放静态文件的目录名不会出现咋URL中。
2).托管多个静态资源目录
如果要托管多个静态资源目录,请多次调用express.static()函数:
3). 挂在路径前缀
app.use('/public' , express.static('public'))
http://localhost:3000/public/images/bg.jpg
http://localhost:3000/public/css/style.css
http://localhost:3000/public/js/login.js
72.nodemon
1).在编写调试node.js项目的时候, 如果修改了项目的代码,则需要频繁的手动close掉,然后再重新启动,非常繁琐。
2).安装nodemon
npm install -g nodemon
3).使用nodemon
node app.js
nodemon app.js (npx nodemon app.js)
73.express路由 - 路由的概念
1.什么是路由
广义来讲,路由就是按键与服务之间的映射关系。
express中的路由:
在express,路由指的是客户端请求与服务器处理函数之间的映射关系。
express中的路由由三部分组成,分别是请求的类型,请求的URL地址、处理函数、格式如下:
app.METHOD(path, handler)
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')
}
2.路由的匹配过程
每当一个请求到达服务器后,需要先经过路由的匹配, 只有匹配成功之后,才会调用对应的处理函数。
在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求URL同时匹配成功,则express会将这次请求,转叫给对应的function函数进行处理
路由匹配的注意点:
1).按照定义的先后顺序进行匹配
2).请求类型和请求URL同时匹配成功。蔡虎调用对应的处理函数。
3.模块化路由
为了方便对路由进行模块化的管理,express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块
1).创建路由模块对应的.js文件
2).调用express.Route()函数创建路由对象
3).向路由对象挂在具体的路由
4).使用module.exports向外共享路由对象
5).使用app.use()函数注册路由模块
4.注册路由模块
5.为路由模块添加前缀
类似于托管静态资源,为静态资源同意挂载访问前缀一样,路由模块添加前缀的方式也非常简单:
74.中间件middleware
中间件的概念与格式
1.中间件特指业务流程中处理环节。中间件一般都有输入与输出,上一级的输出作为下一级的输入
2.express中间件的调用流程
当一个请求到达express的服务器后,可以连续调用多个中间件, 从而对这次请求进行预处理
3.express中间件的格式
express的中间件,本质上就是一个function处理函数,express中间件的格式如下
注意:中间件 函数的形参列表中,必须包含next参数。而路由处理函数中只包含req和res
4.next函数的作用
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
75. 中间件-全局生效的中间件
1).定义中间件函数
2).全局生效的中间件
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件
通过调用app.use(中间件函数),即可定义一个全局生效的中间件,
3).定义全局中间件的简化形式
4).中间件的作用
多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法, 供下游的中间件或路由进行使用 例如:
5). 定义多个全局中间件
76.局部生效的中间件
1).不使用app.use()定义的中间件,叫做局部生效的中间件。示例代码如下:
2).定义多个局部的中间件
77.中间件- 5个注意事项
1).一定要在路由之前注册中间件
2).客户端发送过来的请求,可以连续调用多个中间件进行处理
3).执行完中间件的业务代码之后,不要忘记调用next()函数
4).为了防止代码逻辑的混乱,调用next()函数之后不要再写额外的代码了
5).连续调用多个中间件时,多个中间件之间,共享req和res对象
78.中间件的分类
1).应用级别的中间件
通过app.use()或app.get()或app.post(),绑定到app实例上的中间件,叫做应用级别的中间件
代码示例如下:
//应用级别的中间件(全局中间件)
app.use((req, res, next)=> {
next()
})
//应用级别的中间件(局部中间件)
app.get('/', mw1, (req,res)=> {
res.send('home page')
})
2).路由级别的中间件
绑定到express.Router()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别的中间件没有任何区别。只不过,应用级别的中间件是绑定到app实例上,l路由级别的中间件是绑定到router实例上,代码示例如下
const app = express()
const router = express.Router()
//路由级别的中间件
router.use(function(req, res, next) {
console.log('Time:' + Datenow())
next()
})
app.use('/', router)
3). 错误级别的中间件
错误级别的中间件的作用:专门用来捕获整个项目中发生的错误,从而防止项目异常的崩溃问题。
格式:错误级别中间件的function处理函数中,必须有4个形参,形参顺序从前到后,分别是(err,req,res,next)
app.get('/', function(req,res) { //1.路由
throw new Error('服务器内部发生了错误!') //1.1抛出一个自定义的错误
res.send('Home page')
})
app.use(function(err,req,res,next) { //2.错误级别的中间件
console.log('发生了错误' + err.message) //2.1 在服务器打印错误消息
res.send('Error!' + err.message) //2.2向客户端相应错误相关的内容
})
注意:错误级别中间件必须注册在所有路由之后!
4).Express内置的中间件
自Express4.16.0版本开始,Express内置了3个常用的中间件,极大地提高了Express项目的开发效率和体验:
//配置解析 application/json格式数据的内置中间件
app.use(express.json())
//配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
app.use(express.urlencoded({extended:false}))
5).第三方中间件
非Express官方内置的, 二十由第三方开发出来的中间件, 叫做第三方中间件。 在项目中, 大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
例如:在[email protected]之前的版本中, 经常使用body-parser这个第三方中间件,来解析请求体数据。使用步骤如下:
1).运行npm install body-parser安装中间件
2).使用require导入中间件
3).调用app.use()注册并使用中间件
79. 自定义中间件
1.需求描述与实现步骤
自己手动模拟一个类似于express.urlencoded这样的中间件,来解析POST提交到服务器的表单数据。
实现步骤:
80. 将自定义中间件封装为模块
(见Code2 的13 和14)
81.编写接口-创建基本的服务器创建API路由模块
82编写GET接口 (见 code2 15 和16 )
83 编写post接口
84.编写接口——基于cors解决接口跨域的问题 (见Code2 的17)
Staticfile CDN
刚才编写的GET和POST接口, 存在一个很严重的问题: 不支持跨域请求。
解决跨域问题的方法主要有两种:
1).CORS(主流的解决方案,推荐使用)
2).JSONP(有缺陷的解决方法:支支持GET请求)
使用cors中间件解决跨域问题
cors时express的一个第三方中间件。通过安装和配置cors中间件,可以很方便的解决跨域问题。
使用步骤分为以下三步:
1).运行 npm install cors安装中间件
2).使用const cors = require('cors') 导入中间件
3).在路由之前调用app.use(cors())配置中间件
85.CORS(Cross-Origin Resourse Sharing, 跨域资源共享) 由一系列HTTP响应头组成,这些HTTP响应头决定浏览器是否组织前端JS代码跨域获取资源
浏览器的同源安全策略默认会阻止网页“跨域”获取资源。 但是如果接口服务器配置了CORS相关的HTTP响应头, 就可以接触浏览器端的跨域访问限制。
CORS的注意事项
1).CORS主要在服务器端进行配置。 客户端浏览器无需做任何额外的配置,即可请求开启了CORS的接口。
2).CORS在浏览器中有兼容性。 只支持XMLHttpRequest Level2的浏览器, 才能正常访问开启了CORS的服务器端接口(例如IE10+,chrome4+, FireFox3.5+)
86. 跨域-cors相关的三个响应头
1).CORS 响应头部 Access-Control-Allow-Origin
2).CORS 响应头部 Access-Control-Allow-Headers
3).CORS 响应头部 Access-Control-Allow-Methods
87.跨域-cors的简单请求与预检测请求
客户端在请求CORS接口时,根据请求方式的不同,可以将CORS请求分为两大类,分别是:
1).简单请求:1.请求方式:GET、POST、HEAD三者之一
2.HTTP头部信息不超过以下几种字段:无自定义头部字段、Accpet、Accpet- Language、DPR 、Save-Data、Viewport-Width、Width、Content-Type(只有三个值application/x-www-form-urlencoded\multipart/form-data、text/plain)
2).预检请求:只要符合以下任何一个条件的请求,都需要进行预检请求
1)。请求方式为GET、POST、HEAD之外的请求Method类型
2).请求头中包含自定义头部字段
3).向服务器发送了 application/json格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检, 已获知服务器是否允许该实际请求,所以这一次OPTION请求称为“预检请求”。服务器成功响应遇见请求之后,才会发出真正的请求,并且携带真实的数据。
简单请求与预检请求的区别
简单请求的特点:客户端与服务器之间之会发生一次请求。
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求。
88.跨域 编写jsonp接口
概念:浏览器通过