0
点赞
收藏
分享

微信扫一扫

Node学习资料文档

奋斗De奶爸 2022-04-07 阅读 101

Node.js学习资料文档

FS文件系统模块:

fs.readFile()

  1. 语法格式。

    fs.readFile(path[,options],callback)
    //参数一:必传,字符串,表示文件的路径
    //参数二:可选参数,表示以什么编码格式来读取文件
    //参数三:必传参数,文件读取完成后,通过回调函数拿到读取的结果
    
  2. 实例代码

    console.log("使用fs.readFile()读取文件内容:")
    //导入fs模块,来操作文件
    const fs=require('fs')
    //调用fs.readFile()方法来读取文件
    fs.readFile("a.txt","UTF-8",function(err,data){
    	//如果文件读取失败,err是一个错误对象。读取文件成功返回null
    	if(err){
    		return console.log("读取文件失败:"+err.message)
    	}
    	//如果文件读取成功返回文件内容
    	console.log(data)
    })
    

fs.writeFile()

  1. 语法格式
    使用fs.writeFile()方法,可以向指定的文件中写入内容,语法格式如下:

    fs.writeFile(file,data[,options],callback)
    //参数一:必传参数,需要指定一个文件路径的字符串,表示文件的存放路径
    //参数二:必传参数,表示要写入的内容
    //参数三:可选参数,表示以什么格式写入文件内容,默认是utf8
    //参数四:必传参数,表示文件写入完后都会执行回调函数
    
  2. 实例代码

    console.log("使用fs.writeFile()往文件写入内容:")
    //导入fs模块,来操作文件
    const fs=require('fs')
    //调用fs.writeFile()方法来往文件中写入内容。文件不存在时会创建一个文件,路径不存在出错。只能创建文件不能创建文件夹
    //重复使用fs.writrFile()往一个文件中写入,新写入的会覆盖原来的文件内容
    fs.writeFile("a.txt","哈哈哈哈","UTF-8",function(err){
    	//如果文件文件写入成功,则err的值为null.写入失败err则是一个错误对象
    	if(err){
    		return console.log("往文件写入内容失败:"+err.message)
    	}
    	console.log("文件写入成功!")
    })
    

fs操作文件示例

//引入fs模块,操作文件
const fs=require('fs')
//调用fs.readFile()方法来读取文件
fs.readFile("a.txt","UTF-8",function(err,data){
	//如果文件读取失败,err是一个错误对象。读取文件成功返回null
	if(err){
		return console.log("读取文件失败:"+err.message)
	}
	//如果文件读取成功返回文件内容
	console.log(data)
	//先把读取到的数据按照空格分割
	const arrOld=data.split(" ");
	const arrNew=[];
	arrOld.forEach(item=>{
		//对数组中的=替换为:
		arrNew.push(item.replace("=",":"))
	})
	//对数组中的
	const arrStr=arrNew.join("\r\n")
	//写入文件中
	fs.writeFile("a.txt",arrStr,"UTF-8",function(err){
		//如果文件文件写入成功,则err的值为null.写入失败err则是一个错误对象
		if(err){
			return console.log("往文件写入内容失败:"+err.message)
		}
		console.log("文件写入成功!")
	})
})

fs路径动态拼接问题

在使用fs模块操作文件时,如果提供的操作陆是以./或…/开头的相对路径时,很容易出现路径动态拼接错误的问题。

原因:代码在运行的时候,会以执行node命令时所处的目录,动态拼接出被操作的文件的完整路径。

//出现路径拼接错误问题,使用为提供了./或../开头的相对路径。
//可以提供一个完整的路径,不适用./或../相对路径
//但是移植性非常差,不利于维护
//使用 __dirname 表示当前文件所处的目录
console.log(__dirname)

path路径模块

path模块时Node.js官方提供的,用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。

  • path.join()方法,用来将多个路径片段拼接成一个完整的路径字符串。
  • path.basename()方法,用来从路径字符串中,将文件名解析出来。
  • path.extname()方法,用来从路径字符串中,将文件后缀名解析出来。

如果要在JavaScript代码中,使用path模块来处理路径,则需要使用如下的方式先导入它。

const path = require("path")
//引入path模块,操作路径
const path=require('path')
const pathStr=path.join('/a','/b/c','../','/d/e');
console.log(pathStr)

const pathStr2=path.join(__dirname,"a.txt")
console.log(pathStr2)
//使用path.dasename()方法,可以获取路径中的最后一部分,经常通过这个方法获取路径中的文件名。
const name=path.basename(pathStr2,".txt")
//第一个参数:必传参数,表示一个路径的字符串
//第二个参数:可选参数,表示文件扩展名,如果传了第二个参数,就会在最后得到的String中去掉后缀
//返回:路径字符串中的最后一部分
console.log(name)
//通过path.extname()方法获取文件的后缀名
console.log(path.extname(pathStr2))

今后凡是涉及到路径拼接的操作,都要使用path.join()方法进行处理。不要直接使用+进行字符串的拼接。

Http模块

http模块时Node.js官网提供的,用来创建web服务器的模块。通过http模块提供的http.createServer()方法,就能方便的把一台普通的电脑,变成一台web服务器,从而对外提供web资源服务。

如果要希望使用http模块来创建web服务器,则需要先导入它:

const http = require("http")

创建web服务器

  • 导入http模块
  • 创建web服务器实例
  • 为服务器实例绑定request事件,监听客户端的请求
  • 启动服务器

代码示例:

//导入http模块
const http = require("http")
//创建web服务实例
const server=http.createServer();

//为服务器实例绑定request事件,监听客户端的请求
server.on("request",function(req,res){
	console.log("Someone visit our web server.")
	//req是请求对象,包含了与客户端相关的数据和属性
	//req.url 是客户端请求的url地址
	const url=req.url;
	console.log("请求的url地址为:"+url)
	//req.method 是客户端请求的 method 类型
	const method=req.method;
	console.log("请求的method类型为:"+method)
	//res是响应对象,它包含了与服务器相关的数据和属性
	const str="你请求的地址是"+url+",你请求的method类型为:"+method;
	res.end(str)
})

//调用server.listen(端口号,cb回调)方法,即可启动web服务
server.listen(8080,()=>{
    console.log("WEB Server is runing onLine 127.0.0.1:8080")
})

http模块中解决中文乱码问题:

//设置响应头,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8")

模块化

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。

把代码进行模块化拆分的好处:

  • 提高了代码的复用性
  • 提高了代码的可维护性
  • 可以实现按需加载

Node.js中的模块化:

Node.js中根据模块的来源不同,将模块分为了3打雷,分别是:

  • 内置模块(内置模块是由Node.js 官方提供的,例如 fs、path、http等)
  • 自定义模块(用户创建的每个.js文件,都是自定义模块)
  • 第三方模块(由第三方开发出来的模块,嫔妃官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)

加载模块:

使用强大的require()方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用,例如:

//加载内置fs模块
const fs=require("fs")
//加载用户自定义模块,不写.js后缀名也能加载用户自定义模块
const custom=require("./custom.js")
//加载第三方模块
const moment=require("moment")

注意:使用require()方法加载其他模块时,会执行被加载模块中的代码。

模块作用域:

和函数作用域类似,在自定义模块中定义的变量,方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。

模块作用域的好处:防止全局变量污染的问题。

module对象

在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息。

Module {
  id: '.',
  path: 'D:\\deskBook',
  exports: {},
  filename: 'D:\\deskBook\\a.js',
  loaded: false,
  children: [],
  paths: [ 'D:\\deskBook\\node_modules', 'D:\\node_modules' ]
}

在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用。

外界用require()方法导入自定义模块时,得到的就是module.exports所指向的对象。

//向module.exports对象上挂载username属性
module.exports.username="zs"
//向module.exports对象上挂载hello方法
module.exports.hello=function(){
    consloe.log("hello方法打印")
}

module.exports={
    name="ls"
    ha()=>{
        consloe.log("he方法打印")
    }
}

使用require()方法导入模块时,导入的结果,永远以module.exports指向的对象为准。

由于module.exprots单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象,默认情况下,exporte和module.exports指向同一个对象。最终共享的结果,还是以module.exports指向的对象为准。

npm包可以通过网站:www.npmjs.com 来搜索任何需要的包。还提供了一个下载地址 https://registry.npmjs.org/ 可以通过这个服务器下载所有需要的包。

在项目中安装npm包

npm install 包的完整名称
rem 可以使用简写
npm i 包的完整名称
rem 默认使用该命令下载的包是最新的包,可以在命令后面追加@版本号
  • 使用npm包管理工具,在项目中安装格式化时间的包 moment
  • 使用 require() 导入格式化时间的包
  • 参考 moment 的官方API 文档对时间进行格式化
const moment = require("moment")
moment().formant("YYYY-MM-DD HH-mm-SS")

快速创建package.json

npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理配置文件。

//作用:在执行命令所在处的目录中,快速新建 package.json 文件,目录路径只能在英文路径下
npm init -y

运行npm install命令安装包的时候,npm包管理工具会自动把包的名称和版本号,记录到package.json中。

一次性安装所有的包

可以运行 npm install命令(或npm i)一次性安装所有的依赖包:

//执行 npm install 命令时,npm包管理会先读取 package.json 中的 dependencies 节点。
//读取到记录的所有依赖包名称和版本号之后,npm 包管理工具会把这些包一次性下载到项目中
npm install

从项目中卸载包

可以运行 npm uninstall 命令,来卸载指定的包:

//使用 npm uninstall 具体包名 来卸载包
npm uninstall moment

注意:npm uninstall 命令执行成功后,会把卸载的包,自动从package.json的dependencies 中移除掉

如果某些包只是在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDependencies节点中。与之对应的,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到dependencies节点中。

你可以使用如下命令,将包记录到devDependencies节点中:

//安装指定的包,并记录到devDependencies节点中
npm i 包名 -D
//注意:上述命令是简写形式,等价于下面完整的写法
npm install 包名 --save-dev

解决下包速度慢的问题

使用淘宝npm镜像服务器。

切换npm下包镜像源

# 默认下载镜像源:https://registry.npmjs.org/
# 查看当前的下包镜像源
npm config get registry
# 将下包的镜像源切换为淘宝镜像源
npm config set registry=https://registry.npm.taobao.org/
# 检查镜像源是否下载成功
npm config get registry

nrm工具

为了更方便的切换下包的镜像,我们可以安装nrm这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源。

# 通过npm 包管理器,将nrm安装为全局可用工具
npm i nrm -g
# 查看所有可用的镜像源
nrm ls
# 将下包的镜像源切换为taobao镜像
nrm use taobao

包的分类

使用npm安装的包可用分为两大类:项目包和全局包

那些被安装到项目的 node_modules 目录中的包,都是项目包。

在执行npm install 命令是,如果提供了 -g 参数,则会把包安装为全局包

# 安装全局包
npm i 包名 -g
# 卸载全局安装包
npm uninstall 包名 -g

i5ting_toc

i5ting_toc是一个可用包md文档转为html页面的小工具:

# 全局安装i5ting_toc
npm install -g i5ting_toc
# 调用 i5ting_toc,轻松使用 md 转 html 的功能
i5ting_toc -f 要转换的md文件路径 -o

规范的包结构

在清楚了包的概念,以及如何下载和使用包之后,接下来我们深入了解一下包的内部结构。

一个规范的包,它的组成结构,必须符合一下3个要求:

  • 包必须以单独的目录而存在
  • 包的顶级目录下要必须包含 package.json 这个包管理配置文件
  • package.json 中必包含 name、version、main 这三个属性,分别代表包的名称、版本号、包的入口。

更多规范和约束,可以参考如下网址:

https://yarnpkg.com/zh-Hans/docs/package-json

开发属于自己的包

  • 新建Tool文件夹,作为包的根目录
  • 在Tool文件夹中,新建如下三个文件:
    • package.json(包管理配置文件)
    • index.js(包的入口文件)
    • README.md(包的说明文档)

初始化package.json文件

{
    "name":"Tools",//包名称
    "version":"1.0.0",//包的版本号
    "main":"index.js",//包的入口文件
    "description":"提供了格式化时间,HTMLEscape的功能",//包的简介
    "Keywords":["itheima","dateFormat","escape"],//搜索的关键字
    "license":"ISC"//包遵循的开源许可协议
}

转义HTML的方法。在index.js文件中定义

//转义HTML的方法
function htmlEscape(htmlStr){
	return htmlStr.replace(/<|>|"|&/g,(match)=>{
		switch(match){
			case '<':
			 return '&lt;'
			case '>':
			 return '&gt;'
			case '"'
			 return '&quot;'
			case '&':
			 return '&amp;'
		}
	})
}

//还原HTML的方法
function htmlUnEscape(str){
	return str.replace(/&lt;|&gt;|&quot;|&amp;/g,(match)=>{
		switch(match){
			case '&lt;':
			 return '<'
			case '&gt;':
			 return '>'
			case '&quot;'
			 return '"'
			case '&amp;':
			 return '&'
		}
	})
}

//向外暴露需要的成员
module.exports={
	htmlEscape,htmlUnEscape
}

ES6新特性:...对象名 在一个对象中使用 ...另一个对象 表示把另一个对象的属性 全部添加到该对象中。

注册登录npm
//建议先检查当前下载npm下载包的服务器地址是否是npm官方服务器
npm login 登录名 密码 邮箱

在运行npm login 命令之前,必须先把下包的服务器地址切换为npm的官方服务器。否则会导致发布包失败!

发布包

在登录了用户时,将终端切换到包的根目录之后,运行 npm publish 命令,即可将包发布到npm上(注意:包名不能重复)。

删除已发布的包

运行 npm unpublish 包名 --force 命令,即可从npm删除已发布的包。

通过该命令只能删除72小时以内发布的包,使用该命令删除的包,在24小时内不允许重复发布。发布包的时候要慎重,尽量不要往npm上发布没有意义的包。

模块加载机制

模块在第一次加载后会被缓存。这也意味着多次的require() 不会导致模块的代码被执行多次。

注意:不论是内置模块、用户自定义模块、还是第三方模块,他们都会优先从缓存中加载,从而提高模块的加载效率。

内置模块的加载机制:

内置模块是由Node.js 官方提供的模块,内置模块的加载优先级最高。

例如:require(“fs”) 始终放回内置的fs模块,即使在node_modules目录下有名字相同的包也叫做fs。

自定义模块的加载机制:

使用require() 加载自定义模块是,必须指定义 ./ 或 …/这样的路径标识符,则 node 会把它当作内置模块或第三方模块进行加载。

同时,在使用require() 导入自定义模块是,如果忽略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:

  • 按照确切的文件名进行加载
  • 补全 .js 扩展名进行加载
  • 补全 .json 扩展名进行加载
  • 补全 .node扩展名进行加载
  • 加载失败,终端报错
第三方模块加载机制:

如果传递给require()的模块标识符不是一个内置模块,也没有以 ‘./’ 或 ‘…/’ 开头,则Node.js 会从当前模块的父目录开始,尝试从 /node_modules 文件夹中加载第三方模块。

如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。

目录作为模块:

当把目录作为模块标识符,传递给require()进行加载的时候,有三种加载方式。

  • 在被加载的目录下查找一个叫做 package.json 的文件,并寻找 mian 属性,作为 require() 加载的入口。
  • 如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 将会试图加载目录下的 index.js 文件。
  • 如果以上两步都失败了,则 Node.js 会在终端打印错误消息,报告模块缺失:Error:Cannot find module “XXX”

Express

什么是Express:

官方给出的概念:Express是基于Node.js 平台,快速、开放、极简的Web开发框架。

通俗的理解:Express 的作用和Node.js 内置的 http模块类似,是专门用来创建Web 服务器的。

Express 的本质:就是一个 npm 上的第三方包,提供了快速创建Web服务器的便捷方法。

Express的中文官网:http://www.expressjs.com.cn/

创建服务器

//导入 express
const express = require("express")
//创建web服务器
const app = express()
//启动服务器
app.listen(80, () => {
    console.log("express server is running port 80")
})

监听请求

通过 app.get()方法,可以监听客户端GET 请求,具体的语法格式如下:

//监听客户端的GET请求
//参数一:客户端请求的url地址
//参数二:请求对应的处理函数
//       req:请求对象(包含了于请求相关的属性和方法)
//       res:响应对象(包含了于响应相关的属性和方法)
app.get("/", function (req, res) {
    //通过res.send() 方法可以把数据发送给客户端
    res.send("")
})

通过 app.post()方法,可以监听客户端POST 请求,具体的语法格式如下:

//监听客户端的GET请求
//参数一:客户端请求的url地址
//参数二:请求对应的处理函数
//       req:请求对象(包含了于请求相关的属性和方法)
//       res:响应对象(包含了于响应相关的属性和方法)
app.post("/login", function (req, res) {
    //通过res.send() 方法可以把数据发送给客户端
    res.send("")
})

获取参数:

获取Url中携带的查询参数

通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数。

app.get("/", function (req, res) {
    //通过res.send() 方法可以把数据发送给客户端
    res.send("通过Get方法,请求了/地址")
    //通过req.query对象获取到地址栏中传递的参数:?name=zs&age=20
    //默认req.query是空对象
    console.log(req.query)
})

获取URL中的动态参数

通过req.params 对象,可以访问到URL中,通过:匹配的动态参数。(rest接口)

app.get("/user/:id", function (req, res) {
    //通过res.send() 方法可以把数据发送给客户端
    res.send("通过Get方法,请求了/user/:id地址")
    //req.params 是动态匹配到的 URL 参数,默认是一个空对象。rest请求风格
    console.log(req.params)
})

//请求地址:http://localhost/user/12
//打印出结果为:{ id: '12' }

托管静态资源

express.static()

express 提供了一个非常好用的函数,叫做 express.static(),通过它,我们可以非常方便地创建一个静态资源服务器,例如:通过如下代码就可以将 public 目录下的图片,css文件,javascript文件对外开发访问了。

//静态资源托管
//该静态资源的Tool 需要在Node 执行的js文件同级目录,请求Tool中的静态资源时不需要带Tool,只需在地址栏路径中写:http:ip:prot/{Tool中的资源名称}
app.use(express.static("Tool"))

//托管多个静态资源目录,如果两个目录都有共同的文件,请求时会根据先执行的app.use中查找对应的静态资源
app.use(express.static("files"))

挂载路径的前缀

如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下方式:

//第一个参数代表请求这个静态资源时要携带的地址栏前缀
app.use("/Tool",express.static("Tool"))

nodeMon

在编写调试 Node.js 项目的时候,如果修改了项目代码,则需要频繁的手动 close 掉,然后再重新启动,非常繁琐。

现在,我们可以使用 nodemon (https://www.npmjs.com/package/nodemon) 这个工具,它能够监听项目文件的变动,当代码被修改后,nodemon 会自动帮我们重启项目,极大方便了开发和调试心

安装nodemon

//全局安装 nodemon
npm install -g nodemon

使用nodemon

当基于Node.js编写了一个网站应用的时候,传统的方式,是运行node app.js 命令,来启动项目。这样做的坏处是:代码被修改之后,需要手动重启项目。

现在,我们可以将node命令替换为nodemon命令,使用 nodemon app.js 来启动项目。这样做的好处是:代码被修改之后,会被 nodemon 监听到,从而实现自动重启项目的效果。

//使用nodemon启动项目,在更改项目中的文件时,保存会自动重启项目
nodemon index.js

路由

在Express 中,路由指的是客户端的请求与服务器处理函数之间的映射关系。

Express 中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数,格式如下:

//METHOD:请求类型
//PATH:请求的URL地址
//HANDLER:处理函数
app.METHOD(PATH,HANDLER)

路由匹配过程

每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数。

在匹配时,会按照路由的顺序进行匹配,如果请求类型请求的URL同时匹配成功,则 Express 会将这次请求,转交给对应的function函数进行处理。

路由最简单的使用方法:

app.get("/", (req, res) => {res.send("通过Get方法,请求了/地址")})

app.post("/login", (req, res) => {res.send("通过Post方法,请求了/login地址")})

模块化路由:

为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。

将路由抽离为单独模块的步骤如下:

  • 创建路由模块对应的.js文件
  • 调用 express.Router() 函数创建路由对象
  • 向路由对象上挂载具体的路由
  • 使用module.exports 向外共享路由对象
  • 使用app.use() 函数注册路由模块
创建路由模块
//这是路由模块
const express = require("express")
//创建路由对象
const router = express.Router();

//挂载具体的路由
router.get("/", ((req, res) => {
    res.send("Get 请求/")
}))

router.post("/login", ((req, res) => {
    res.send("post 请求/login")
}))

//向外导出路由对象
module.exports = router
使用路由模块
//导入 express
const express = require("express")
//导入自定义的路由模块
const router = require("./router");

//创建web服务器
const app = express()

//app.use()函数的作用,就是用来注册全局中间件
//注册路由模块,使它生效
app.use(router)

//启动服务器
app.listen(80, () => {
    console.log("express server is running port 80")
})
路由模块添加统一的访问前缀:
//app.use()函数的作用,就是用来注册全局中间件
//注册路由模块,使它生效
//第一个参数:/api 代表给路由模块中的所有接口都添加统一的请求前缀
app.use("/api", router)

中间件

中间件(Middleware ) ,特指业务流程的中间处理环节。

当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理

Express的中间件,本质就是一个 function 处理函数。

app.get("/",function(req,res,next){ next() })

注意:中间件函数的形参列表中,必须包含next 参数。而路由处理函数只包含req和res。

中间件的作用:

多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。

next 函数的作用:

next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。

全局中间件:

客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件。

使用app.use(中间件函数),即可定义一个全局生效的中间件。实例代码。

const middleware = function (req, res, next) {
    console.log("我是一个全局中间件件")
    //把流转关系,转交给下一个中间件或路由
    next()
}

//创建web服务器
const app = express()

//注册全局中间件
app.use(middleware)
简化版
//创建web服务器
const app = express()

//注册全局中间件
app.use(function (req, res, next) {
    console.log("我是一个全局中间件件")
    //把流转关系,转交给下一个中间件或路由
    next()
});
举报

相关推荐

0 条评论