NodeJS笔记

1、node、npm安装及使用

NPM(Node Package Manager)是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:

1)允许用户从NPM服务器下载别人编写的第三方包到本地使用。
2)允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
3)允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
由于新版的nodejs已经集成了npm,所以之前npm也一并安装好了。同样可以通过输入 "npm -v" 来测试是否成功安装。命令如下,出现版本提示表示安装成功:

1)node、npm

(1)安装node、npm
可以直接在官方网站中下载安装,安装完成可以使用node -vnpm -v进行检查是否安装成功

node -v
npm -v

(2)安装webpack:不需要手动安装了

npm install webpack -g

(3)使用taobao镜像加速

npm install -g cnpm --registry=https://registry.npmmirror.com/
  • 切换npm下载源
//查看当前包的镜像源
npm config get registry
//设置镜像源为淘宝镜像
npm config set registry=https://registry.npmmirror.com/
  • package.json
    npm规定,在项目根目录中,必须提供一个叫做package.json的包管理配置文件。用来记录与项目有关的一些配置信息,如:

①项目的名称、版本号、描述等
②项目中都用到了哪些包
③哪些包只在开发期间会用到
④哪些包在开发和部署时都会用到

  • 初次安装后项目会多如下文件:

node_modules文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就算从这个目录中查找并加载包。
package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等。

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

  • 快速创建package.json
    npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速的创建package.json这个包管理配置文件。
npm init -y
  • 可以运行npm install命令(或者npm i)一次性安装所有的包.
npm install
  • 可以运行npm uninstall命令来卸载指定的包
npm uninstall moment

2)nrm

nrm(npm registry manager)是 npm 镜像源管理工具,用于快速地在不同的 npm 源之间切换。在中国大陆,由于网络的原因,npm 的默认源可能会出现下载速度较慢或者无法访问的情况,nrm 可以帮助开发者快速地切换到可用的源,提高包的下载速度

  • 安装:
npm i -g nrm
  • 使用:
//查看可以用的镜像
nrm ls 
//测试镜像的速度
nrm test 
//切换镜像
nrm use 镜像名称 

3)pnpm

优势:比同类工具快2倍左右、节省磁盘空间
安装方式:npm install -g pnpm
创建vue项目:pnpm create vue
image

4)nvm

nvm(Node Version Manager)是 Node.js 版本管理工具,可以方便地在同一台机器上安装、管理多个 Node.js 版本。由于不同的项目可能需要使用不同的 Node.js 版本,nvm 可以帮助开发者快速地在不同的 Node.js 版本之间切换,避免版本冲突的问题。
下载好nvm-windows.exe,使用管理员权限,一路下一步,遇到选择安装目录时,尽量选择非C盘的目录,避免出现权限问题!

5)nodemon

nodemon用来监视node.js应用程序中的任何更改并自动重启服务,非常适合用在开发环境中。以前,我们开发一个node后端服务时,每次更改文件,均需重启一下,服务才能生效。这使我们的开发效率降低了很多。

nodemon的出现,可以随时监听文件的变更,自动重启服务,我们开发时只需关注代码即可,不再需要手动重启服务。

  • 安装:
npm install -g nodemon
  • 启动:
nodemon [your node app]

6)包分类

  • 项目包
    那些被安装到项目的node_modules目录中的包,都是项目包。
    项目包又分为两类,分别是:

①开发依赖包(被记录到devDependencies节点中的包,只在开发时期会用到)
②核心依赖包(被记录到dependencies节点中的包,在开发期间和项目上线之后都会用到)

//开发依赖包
npm i 包名 -D
//核心依赖包
npm i 包名
  • 全局包
    在执行npm install命令时,如果提供了-g参数,则会把包安装为全局包。

全局包会被安装到:C:\Users\用户名\AppData\Roaming\npm\node_modules目录下

//全局安装指定的包
npm i 包名 -g
//全局卸载指定的包
npm uninstall 包名 -g

注意:
①只有工具性质的包,才有全局安装的必要性,因为他们提供了好用的终端命令。
②判断某个包是否需要全局安装后才能使用,可以参考官方提供的使用说明即可。

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

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

2、Node.js 文件系统:fs

Node.js 提供一组类似 UNIX(POSIX)标准的文件操作API。 Node 导入文件系统模块(fs)语法如下所示:

var fs = require("fs")
//读取指定文件中的内容:path表示文件的路径,options表示以什么编码格式来读取文件,
//callback文件读取完成后,通过回调函数拿到读取的结果
fs.readFile(path[,options],callback)
//向指定文件中写入内容:path表示文件路径,data表示要写入的内容
//options表示以什么格式写入文件,默认utf8,callback文件写入完成的回调函数
fs.writeFile(file,data[,options],callback)

1)读取文件:

点击查看代码
const fs = require("fs")

fs.readFile("./test.text", 'utf8', function (err, dataStr) {
    if (err) return console.log("读取文件失败" + err.message)
    console.log("读取文件成功" + dataStr)
})
### 2)写入文件:
点击查看代码
const fs = require("fs")
const { func } = require("joi")

fs.writeFile('./test.txt', 'hello 你好', 'utf8', function (err) {
    if (err) return console.log("文件写入失败" + err.message)
    console.log("文件写入成功")
})

3)异步和同步:

Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。
异步的方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。
建议大家使用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。

3、Node.js GET/POST请求:http模块

http模块是node.js官方提供的用来创建web服务器的模块。通过http模块提供的CreateServer()方法来实现。
使用步骤:

点击查看代码
//导入
const http=require("http")
//创建web服务器实例
const server=http.CreateServer()
//为服务器实例绑定request事件,监听客户端的请求
server.on('request',(req,res)=>{
	console.log('new request')
})
//启动服务器
server.listen(80,()=>{
	console.log("running at 127.0.0.1:80")
})

只要服务器接收到了客户端的请求,就会调用通过server.on()为服务器绑定的request事件处理函数。可以使用如下方法在事件处理函数中访问与客户端相关的数据或者属性:

(1)request.url:是客户端请求的URL地址
(2)request.method:是客户端请求的类型
(3)response.end():向客户端发送指定的内容,并结束这次请求的处理过程。

end()中文乱码处理:response.setHeader("Content-Type","text/html;charset=utf-8")

1)获取GET请求内容

由于GET请求直接被嵌入在路径中,URL是完整的请求路径,包括了?后面的部分,因此你可以手动解析后面的内容作为GET请求的参数。

node.js 中 url 模块中的 parse 函数提供了这个功能。

2)获取 URL 的参数

3)获取 POST 请求内容

4、Node.js 工具模块

Path 模块

OS 模块

Net 模块

5、模块化

为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。

模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。

1)node.js中模块的分类

根据模块来源的不同,将模块分为了3类:

(1)内置模块(内置模块是由Node.js官方提供的,例如:fs、path、http等)
(2)自定义模块(用户创建的每个js文件,都是自定义模块)
(3)第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户自定义模块,使用前需要先下载),又叫包。

2)加载模块

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

点击查看代码
//加载内置fs模块
const fs=require("fs")
//加载用户自定义模块
const custom=require("./custom.js")
//加载第三方模块
const moment=require("moment")

3)模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内访问,这种模块级别的访问限制,叫做模块作用域。
image
模块作用域好处:防止了全局变量污染的问题

4)向外共享模块作用域中的成员

(1)module对象:

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

image
(2)module.exports对象:

在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用。外界用requre()方法导入自定义模块时,得到的就是module.exports所指向的对象。

把一个对象封装到模块中,格式如下:

module.exports = function() {
  // ...
}

引入模块:

点击查看代码
//main.js 
var Hello = require('./hello'); 
hello = new Hello(); 
hello.setName('BYVoid'); 
hello.sayHello(); 

hello.js文件

点击查看代码
//hello.js 
function Hello() { 
    var name; 
    this.setName = function(thyName) { 
        name = thyName; 
    }; 
    this.sayHello = function() { 
        console.log('Hello ' + name); 
    }; 
}; 
module.exports = Hello;

共享成员时的注意点:

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

(3)exports对象:

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

引入模块:

var hello = require('./hello');
hello.world();

hello.js文件:

//hello.js 
exports.world = function() {
  console.log('Hello World');
}

image

时刻谨记:
require()模块时,得到的永远是module.exports指向的对象。为了防止混乱,建议大家不要再同一个模块中同时使用exports和module.exports。
image
exports 和 module.exports 的使用:

如果要对外暴露属性或方法,就用 exports 就行,要暴露对象(类似class,包含了很多属性和方法),就用 module.exports。

5)Node.js中的模块化规范

Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如果相互依赖。
CommonJS规定:

①每个模块内部,module变量代表当前模块
②module变量是一个对象,它的exports属性(即module.exports)是对外的接口
③加载某个模块,其实是加载该模块的module.exports属性,require()方法用于加载模块

6、Node.js Express 框架

Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。(和node.js内置的http模块类似)
使用 Express 可以快速地搭建一个完整功能的网站或者API接口服务器。

Express 框架核心特性:
①可以设置中间件来响应 HTTP 请求。
②定义了路由表用于执行不同的 HTTP 请求动作。
③可以通过向模板传递参数来动态渲染 HTML 页面。

cnpm install express --save

以上命令会将 Express 框架安装在当前目录的 node_modules 目录中, node_modules 目录下会自动创建 express 目录。
以下几个重要的模块是需要与 express 框架一起安装的:

①body-parser - node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据。
②cookie-parser - 这就是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。
③multer - node.js 中间件,用于处理 enctype="multipart/form-data"(设置表单的MIME编码)的表单数据。

cnpm install body-parser --save
cnpm install cookie-parser --save
cnpm install multer --save

安装完后,我们可以查看下 express 使用的版本号:

cnpm list express

使用:创建基本的web服务器

const  express=require("express")
const app=express()
app.listen(80,()=>{
	console.log("running on 80")
})

1)监听GET和POST请求&处理参数

①通过request.query可以获取客户端发送过来的查询参数,默认为空
②通过request.params对象,可以访问到URL中,通过:匹配到的动态参数
③通过request.body访问表单数据(需要先配置中间件)

(1)监听GET请求
通过app.get(),可以监听客户端的GET请求:

//参数1:客户端url
//参数2:请求处理函数
app.get('/get?name=zs',function(req,res){
    res.send(req.query)
})

(2)把内容响应给客户端
通过response.send()方法,可以把处理好的内容,发送给客户端:

app.get('/getURL',function(request,response){
	response.send({name:"zs",age:20})
})

(3)监听POST请求
通过app.post(),可以监听客户端的GET请求:

// 需要配置中间件,然后再使用req.body获取
app.use(express.urlencoded({
    extended:true
}))
app.post('/post',(req,res)=>{
    console.log(req)
    res.send(req.body)
})

(4)动态参数
通过app.get(),可以监听客户端的GET请求:

//参数1:客户端url
//参数2:请求处理函数
app.get('/get/:id',function(req,res){
    res.send(req.params)
})

2)托管静态资源

(1)express.static()
express提供了一个非常好用的函数,express.static(),通过它,可以非常方便的创建一个静态资源服务器。

app.use(express.static("./clock"));

访问:http://127.0.0.1/clock.html
(2)挂载路径前缀
如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以通下述方式:

app.use("clock",express.static("./clock"));

访问:http://127.0.0.1/clock/clock.html
目录结构:
image

3)express路由

(1)简单路由:
在Express中使用路由最简单的方式,就是把路由挂载到app 上。
请见【监听GET和POST请求&处理参数】
(2)模块化的路由
为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到app 上,而是推荐将路由抽离为单独的模块。将路由抽离为单独模块的步骤如下:

①创建路由模块对应的.js文件
②调用express.Router()函数创建路由对象
③向路由对象上挂载具体的路由
④使用module.exports向外共享路由对象
⑤使用app.use()函数注册路由模块:
app.use()函数的作用就是用来注册全局中间件
app.use(express.static('./files'))上节的静态托管资源
app.use(router)本节的注册路由

image
类似于托管静态资源时,为静态资源统一挂载访问前缀一样,路由模块添加前缀的方式如下:

app.use("/api",router);

4)express中间件

中间件(Middleware ) ,特指业务流程的中间处理环节。
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。
Express的中间件,本质上就是一个function处理函数,Express中间件的格式如下:
image
中间件函数的形参列表中,必须包含next参数。而路由处理函数中只包含reqres
next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
(1)全局生效的中间
客户端发起的任何请求,到达服务器之后,都会触发的中间件,叫做全局生效的中间件。通过调用app.use(中间件函数),即可定义一个全局生效的中间件,示例代码如下:

点击查看代码
const express = require("express");
const app = express();

//使用req.body需要先配置此中间件
app.use(
  express.urlencoded({
    extended: true,
  })
);

const mw = function (req, res, next) {
  console.log("这个是简单的中间件");
  next();
};
app.use(mw);
app.use("/clock", express.static("./clock"));

const router = require("./router");
app.use("/api", router);

app.listen(80, (req, res) => {
  console.log("running on 80...");
});

定义全局中间件的简化形式

app.use((req, res, next)=>{
  console.log("这个是简单的中间件");
  next();
})

多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由进行使用。
可以使用app.use()连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用。
(2)局部生效的中间
不使用app.use()定义的中间件,叫做局部生效的中间件,示例代码如下:

点击查看代码
const express = require("express");
const app = express();

//使用req.body需要先配置此中间件
app.use(
  express.urlencoded({
    extended: true,
  })
);

const mw = function (req, res, next) {
  console.log("这个是简单的中间件");
  next();
};

app.use("/clock", express.static("./clock"));

const router = require("./router");
app.use("/api",mw, router);

app.listen(80, (req, res) => {
  console.log("running on 80...");
});

可以在路由中,通过如下两种等价的方式,使用多个局部中间件:

点击查看代码
const express = require("express");
const app = express();

//使用req.body需要先配置此中间件
app.use(
  express.urlencoded({
    extended: true,
  })
);

const mw1 = function (req, res, next) {
  console.log("这个是简单的中间件1");
  next();
};

const mw2 = function (req, res, next) {
  console.log("这个是简单的中间件2");
  next();
};

app.use((req, res, next)=>{
  console.log("这个是简单的中间件");
  next();
})

//app.use(mw);

app.use("/clock", express.static("./clock"));

const router = require("./router");
app.use("/api",mw1,mw2, router);

app.listen(80, (req, res) => {
  console.log("running on 80...");
});

(3)中间件的5个使用注意事项
①一定要在路由之前注册中间件
②客户端发送过来的请求,可以连续调用多个中间件进行处理
③执行完中间件的业务代码之后,不要忘记调用next()函数
④为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
⑤连续调用多个中间件时,多个中间件之间,共享req和res对象
(4)中间件分类
应用级别中间件通过app.use()或app.get()或 app.post(),绑定到app实例上的中间件,叫做应用级别的中间件,代码示例如下:

app.use((req, res, next) => {
  console.log("这个是简单的中间件");
  next();
});

路由级别中间件:(必须定义在所有路径的最前面)
绑定到express.Router()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到app 实例上,路由级别中间件绑定到 router实例上,代码示例如下:

点击查看代码
const express = require("express");
const app = express();
const router = express.Router();

router.use(function (req, res, next) {
  console.log("路由级别中间件");
  next();
});

router.get("/get", function (req, res) {
  res.send(req.query);
});
app.use("/", router);

app.listen(80, (req, res) => {
  console.log("running on 80...");
});

错误级别中间件:错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
格式∶错误级别中间件的function处理函数中,必须有4个形参,形参顺序从前到后,分别是(err, req, res, next)

app.get("/", (req, res) => {
  throw new Error("服务器发生内部错误");
});

app.use((err, req, res, next) => {
  console.log("发生了错误" + err.message);
  res.send("Error" + err.message);
});

错误级别中间件,必须注册在所有路由之后。
(5)自定义中间件:
TODO
(6)express内置中间件:
express内置了三个常见的中间件:
express.static:快速托管静态资源
express.json:解析JSON格式的请求体数据(有兼容性问题)
express.urlencoded:解析URL-encoded格式的请求提数据(有兼容性问题)
(7)第三方中间件
如:body-parser

5)使用express写接口

7、Node.js 连接 MySQL

8、Node.js 全局对象

1)__filename

__filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。

2)__dirname

__dirname 表示当前执行脚本所在的目录。

3)setTimeout(cb, ms)

setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。:setTimeout() 只执行一次指定函数。
返回一个代表定时器的句柄值。

4)clearTimeout(t)

clearTimeout( t ) 全局函数用于停止一个之前通过 setTimeout() 创建的定时器。 参数 t 是通过 setTimeout() 函数创建的定时器。

5)setInterval(cb, ms)

setInterval(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。
返回一个代表定时器的句柄值。可以使用 clearInterval(t) 函数来清除定时器。
setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。

6)console

console 用于提供控制台标准输出,它是由 Internet Explorer 的 JScript 引擎提供的调试工具,后来逐渐成为浏览器的实施标准。
Node.js 沿用了这个标准,提供与习惯行为一致的 console 对象,用于向标准输出流(stdout)或标准错误流(stderr)输出字符。

7)process

process 是一个全局变量,即 global 对象的属性。
process 是一个全局变量,即 global 对象的属性。
它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要 和它打交道。下面将会介绍 process 对象的一些最常用的成员方法。它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要 和它打交道。下面将会介绍 process 对象的一些最常用的成员方法。

posted @ 2024-05-14 20:10  权杖攻城狮  阅读(36)  评论(0编辑  收藏  举报