Node.js详解——part02
01包管理工具
1.概念介绍
1.1 包是什么
『包』英文单词是 package ,代表了一组特定功能的源码集合
1.2 包管理工具
管理『包』的应用软件,可以对「包」进行 下载安装 , 更新 , 删除 , 上传 等操作
借助包管理工具,可以快速开发项目,提升开发效率
包管理工具是一个通用的概念,很多编程语言都有包管理工具,所以 掌握好包管理工具非常重要
1.3 常用的包管理工具
下面列举了前端常用的包管理工具
- npm
- yarn
- cnpm
2.npm
npm 全称 Node Package Manager ,翻译为中文意思是『Node 的包管理工具。
npm 是 node.js 官方内置的包管理工具,是 必须要掌握住的工具。
2.1 npm 的安装
node.js 在安装时会 自动安装 npm ,所以如果你已经安装了 node.js,可以直接使用 npm。可以通过 npm -v 查看版本号测试,如果显示版本号说明安装成功,反之安装失败。

2.2 npm 基本使用
2.2.1 初始化
创建一个空目录,然后以此目录作为工作目录 启动命令行工具 ,执行 npm init

package.json文件内容展示:

npm init 命令的作用是将文件夹初始化为一个『包』, 交互式创建 package.json 文件。
package.json 是包的配置文件,每个包都必须要有 package.json。
属性翻译:
{
"name": "1-npm", #包的名字
"version": "1.0.0", #包的版本
"description": "", #包的描述
"main": "index.js", #包的入口文件
"scripts": { #脚本配置
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "", #作者
"license": "ISC" #开源证书
}
注意事项:
1.package name ( 包名 ) 不能使用中文、大写,默认值是 文件夹的名称 ,所以文件夹名称也不能使用中文和大写
2.version ( 版本号 )要求 x.x.x 的形式定义, x 必须是数字,默认值是 1.0.0
3.ISC 证书与 MIT 证书功能上是相同的,关于开源证书扩展阅读http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html
4.package.json 可以手动创建与修改
5.使用 npm init -y 或者 npm init --yes 极速创建 package.json
2.2.2 搜索包
搜索需要使用的包的方式有两种
- 命令行 『npm s/search 关键字』

- 网站搜索 网址是 https://www.npmjs.com/

2.2.3安装包
通过npm install 和 npm i 命令安装包(这是局部安装,只能在安装此依赖的目录下使用,出了该目录就使用不了了)
示例:npm i uniq
安装完成后使用包:
1.导入包 const uniq = require(‘uniq’)
2.使用:console.log(uniq(arr))
2.3生产依赖和开发依赖
在安装时可以选择要安装的依赖的类型:
| 类型 | 命令 | 补充 |
|---|---|---|
| 生产依赖 | 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属性中 |
2.4全局安装
我们可以执行安装选项-g 进行全局安装,局部安装的依赖通过require来使用,全局安装的依赖通过命令行来使用。
npm i -g nodemon
全局安装完成之后就可以在命令行的任何位置运行 nodemon 命令。
该命令的作用是 自动重启 node 应用程序。
1.全局安装的命令不受工作目录位置影响
2.可以通过 npm root -g 可以查看全局安装包的位置
3.不是所有的包都适合全局安装 , 只有全局类的工具才适合,可以通过查看包的官方文档来确定
2.5安装包依赖
在项目协作中有一个常用的命令就是 npm i ,通过该命令可以依据 package.json 和 package
lock.json的依赖声明安装项目依赖。(在刚进入到一个项目拉取下来代码之后,首先需要进行npm i来安装代码需要使用到的所有依赖)
2.6安装指定版本的包和删除依赖
安装
npm i 包名@版本号
npm i jquery@1.11.2
删除
局部删除
npm remove uniq
全局删除
npm remove -g nodemon
2.7npm配置命令别名
通过配置命令别名可以更简单的执行命令
配置 package.json 中的 scripts 属性
{
.
.
"scripts": {
"server": "node server.js",
"start": "node index.js",
},
.
.
}
配置完成之后,可以使用别名执行命令
npm run server
npm run start //start比较特别,可以省略run,直接 npm start
补充说明:
npm start 是项目中常用的一个命令,一般用来启动项目
npm run 有自动向上级目录查找的特性,跟 require 函数也一样
对于陌生的项目,我们可以通过查看 scripts 属性来参考项目的一些操作
3.cnpm
3.1介绍
cnpm 是一个淘宝构建的 npmjs.com 的完整镜像,也称为『淘宝镜像』,网址https://npmmirror.com/
cnpm 服务部署在国内 阿里云服务器上 , 可以提高包的下载速度
官方也提供了一个全局工具包 cnpm ,操作命令与 npm 大体相同
3.2安装
通过npm来安装cnpm
npm install -g cnpm --registry=https://registry.npmmirror.com
3.3操作命令
| 功能 | 命令 |
|---|---|
| 初始化 | cnpm init |
| 安装包 | 1.cnpm i uniq 2.cnpm i -S uniq 3.cnpm i -D uniq 4.cnpm i -g nodemon |
| 安装项目依赖 | cnpm i |
| 删除 | cnpm r uniq |
3.4npm配置淘宝镜像
用 npm 也可以使用淘宝镜像,配置的方式有两种
直接配置
使用如下命令即可完成配置
npm config set registry https://registry.npmmirror.com/
工具配置
1.安装nrm
npm i -g nrm
2.修改镜像
nrm use taobao
3.检查是否配置成功
npm config list
4.yarn
4.1yarn介绍
yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方网址:https://yarnpkg.com/
4.2yarn特点
yarn 官方宣称的一些特点
速度超快:yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大
化资源利用率,因此安装速度更快
超级安全:在执行代码之前,yarn 会通过算法校验每个安装包的完整性
超级可靠:使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的工作
4.3yarn的安装以及常用命令
安装
npm i -g yarn
常用命令
| 功能 | 命令 |
|---|---|
| 初始化 | yarn init/yarn init -y |
| 安装包 | yarn add uniq 生产依赖 yarn addless --dev 开发依赖 yarn global add nodemon 全局安装 |
| 删除包 | yarn remove uniq 删除项目依赖包 yarn global remove nodemon 全局删除包 |
| 安装项目依赖 | yarn |
| 运行命令别名 | yarn 别名(不需要添加run) |
| 查看yarn全局安装包的位置 | yarn global bin |
注意:这里有个小问题就是 全局安装的包不可用 ,yarn 全局安装包的位置可以通过 yarn lobal bin来查看,然后将该位置配置到环境变量中即可使用。
4.4yarn配置淘宝镜像
可以使用如下命令配置yarn的淘宝镜像
yarn config set registry https://registry.npmmirror.com/
可以通过 yarn config list 查看 yarn 的配置项
注意:包管理工具不要混着用
5.nvm
介绍
vm 全称 Node Version Manager 顾名思义它是用来管理 node 版本的工具,方便切换不同版本的Node.js
下载安装
首先先下载 nvm,下载地址 https://github.com/coreybutler/nvm-windows/releases,选择 nvm-setup.exe 下载即可
常用命令
| 命令 | 说明 |
|---|---|
| nvm list available | 显示所有可以下载的Node.js版本 |
| nvm list | 显示已安装的版本 |
| nvm install 16.18.0 | 安装16.18.0版本的Node.js(下载完后需要使用) |
| nvm install latest | 安装最新版本的Node.js |
| nvm uninstall 16.18.0 | 删除某个版本的Node.js |
| nvm use 16.18.0 | 切换16.18.0的Node.js |
02express框架
2.1介绍
express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架,官方网址:https://www.expressjs.com.cn/
简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)

2.2使用
下载安装
npm init
npm i express
使用步骤
// 导入express
const express = require('express')
// 创建应用对象
const app = express()
// 创建路由
app.get('/',(req,res)=>{
res.end("hello")
})
// 监听端口,启动服务
app.listen(8000,()=>{
console.log("服务已经启动,8000端口正在监听中......")
})
命令行下执行该脚本
node xxx.js
或者
nodemon xxx.js
2.3路由
路由确定了应用程序如何响应客户端对特定端点的请求。
路由的使用
一个路由的组成有请求方法、 路径和回调函数组成。
express 中提供了一系列方法,可以很方便的使用路由,使用格式如下:
app.<method>(path,callback)
// 导入express
const express = require('express')
// 创建应用对象
const app = express()
// 创建路由1
app.get('/hello', (req, res) => {
res.end("hello")
})
// 创建路由2
app.post('/world', (req, res) => {
res.end("world")
})
//匹配所有的请求方法 路由3
app.all('/search', (req, res) => {
res.send('1 秒钟为您找到相关结果约 100,000,000 个');
})
//自定义 404 路由(以上路由均匹配不到时,响应这个路由)
app.all("*", (req, res) => {
res.send('<h1>404 Not Found</h1>')
})
// 监听端口,启动服务
app.listen(8000, () => {
console.log("服务已经启动,8000端口正在监听中......")
})
2.4获取请求参数
express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式。
app.get('/hello', (req, res) => {
//1. 获取报文的方式与原生 HTTP 获取方式是兼容的
// console.log(req.method)
// console.log(req.url)
// console.log(req.httpVersion)
// console.log(req.header)
//2. express 独有的获取报文的方式
//获取查询字符串
console.log(req.query); // 『相对重要』
// 获取指定的请求头
console.log(req.get('host'));
console.log(req.get('Connection'))
res.end("hello")
})
2.5获取路由参数
路由参数指的是URL路径中的参数(数据)


app.get('/:xxx.html', (req, res) => {
res.send('商品详情, 商品 id 为' + req.params.xxx);
}); //即可获取到

2.6express响应设置
// 导入express
const express = require('express')
// 创建应用对象
const app = express()
// 创建路由1
app.get('/hello', (req, res) => {
//1. express 中设置响应的方式兼容 HTTP 模块的方式
// res.statusCode = 404;
// res.statusMessage = 'find fault';
// res.setHeader('abc', 'xyz');
// res.write('response');
// res.end('HTTP');
//2. express 的响应方法
res.status(500); //设置响应状态码
res.set('xxx', 'yyy');//设置响应头
res.send('中文响应不乱码');//设置响应体
//连贯操作
res.status(404).set('xxx', 'yyy').send('你好朋友')
//3. 其他响应
res.redirect('http://www.baidu.com')//重定向
res.download(__dirname + '/index.html');//下载响应
res.json();//响应 JSON
res.sendFile(__dirname + '/index.html') //响应文件内容
})
// 监听端口,启动服务
app.listen(8000, () => {
console.log("服务已经启动,8000端口正在监听中......")
})
2.7中间件
2.7.1认识中间件
中间件(Middleware)本质是一个回调函数。
中间件函数可以像路由回调一样访问请求对象(request), 响应对象(response)。
作用中间件的作用就是使用函数封装公共操作,简化代码。
类型全局中间件和路由中间件
2.7.2全局中间件
定义全局中间件
let recordMiddleware = function(request,response,next){
//实现功能代码
//.....
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
//应用中间件
app.use(recordMiddleware)
声明时可以直接将匿名函数传递给 use
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
})
定义多个全局中间件
app.use(function (request, response, next) {
console.log('定义第一个中间件');
next();
})
app.use(function (request, response, next) {
console.log('定义第二个中间件');
next();
})
案例
// 导入express
const express = require('express')
const fs = require('fs')
const path = require('path')
// 创建应用对象
const app = express()
// 将每次的请求记录保存到文件request.log中
let recordMiddleware = function (request, response, next) {
let { url, ip } = request
//实现功能代码
fs.appendFileSync(path.resolve(__dirname, './access.log'), `${url} ${ip}\r\n`)
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
app.use(recordMiddleware)
// 创建路由1
app.get('/hello', (req, res) => {
res.send('前台首页')
})
app.get('/home', (req, res) => {
res.send('后台首页')
})
// 监听端口,启动服务
app.listen(8000, () => {
console.log("服务已经启动,8000端口正在监听中......")
})
2.7.3路由中间件
如果 只需要对某一些路由进行功能封装 ,则就需要路由中间件
调用格式如下:
let recordMiddleware1 = function(request,response,next){
//实现功能代码
//.....
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
let recordMiddleware2 = function(request,response,next){
//实现功能代码
//.....
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
app.get('/路径',recordMiddleware1,(request,response)=>{
});
app.get('/路径',recordMiddleware1,recordMiddleware2,(request,response)=>{
});
案例
// 导入express
const express = require('express')
const fs = require('fs')
const path = require('path')
// 创建应用对象
const app = express()
// 将每次的请求记录保存到文件request.log中
let recordMiddleware = function (request, response, next) {
let { url } = request
console.log(request)
//实现功能代码
fs.appendFileSync(path.resolve(__dirname, './access1.log'), `${url}\r\n`)
//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)
next();
}
// 创建路由1
app.get('/index', recordMiddleware,(req, res) => {
res.send('前台首页')
})
app.get('/reg', (req, res) => {
res.send('后台首页')
})
// 监听端口,启动服务
app.listen(8000, () => {
console.log("服务已经启动,8000端口正在监听中......")
})
2.7.4静态资源中间件
//引入express框架
const express = require('express');
//创建服务对象
const app = express();
//静态资源中间件的设置,将当前文件夹下的public目录作为网站的根目录
app.use(express.static('./public')); //当然这个目录中都是一些静态资源
//如果访问的内容经常变化,还是需要设置路由
//但是,在这里有一个问题,如果public目录下有index.html文件,单独也有index.html的路由,
//则谁书写在前,优先执行谁
app.get('/index.html',(request,response)=>{
respsonse.send('首页');
});
//监听端口
app.listen(8000,()=>{
console.log('8000 端口启动....');
});
注意事项:
1.index.html 文件为默认打开的资源
2.如果静态资源与路由规则同时匹配,谁先匹配谁就响应
3.路由响应动态资源,静态资源中间件响应静态资源
2.8获取请求体数据body-parser
express可以使用body-parser包处理请求体
第一步:安装
npm i body-parser
第二步:导入body-parser包
const bodyParser = require('body-parser')
第三步:获取中间件函数
处理querstring格式的请求体: let urlParser = bodyParser.urlencoded({extended:false});
处理JSON格式的请求体:let jsonParser = bodyParser.json();
第四步:设置路由中间件,然后使用request.body来获取请求体数据
(中间件函数执行完之后就会给req身上添加上一个属性body,这样就可以获得请求体的内容了)
app.post('/login', urlParser, (request,response)=>{
//获取请求体数据
//console.log(request.body);
//用户名
console.log(request.body.username);
//密码
console.log(request.body.userpass);
response.send('获取请求体数据');
});
获取到的请求体数据
[Object: null prototype] { username: 'admin', userpass: '123456' }
2.9防盗链
设置防盗链的作用:防止本网站的资源被其他网站使用。通过请求头中的referer来检测。
app.use((req,res,next)=>{
//检测请求头中的referer是否为127.0.0.1(自己服务的hostname)
//获取referer
let referer = req.get('referer');
if(referer){
//实例化
let url = new URL(referer);
//获取hostname
let hostname = url.hostname;
//判断
if(hostname!=='127.0.0.1'){
//响应404
res.status(404).send('<h1>404 Not Found</h1>');
return
}
}
next();
})
2.10路由模块化——Router
什么是Router
express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。
作用
对路由进行模块化,更好的管理路由
使用

03EJS模板引擎
3.1什么是模板引擎
模板引擎是分离用户界面和业务数据的一种技术
3.2什么是EJS
EJS 是一个高效的 Javascript 的模板引擎
官网: https://ejs.co/
中文站:https://ejs.bootcss.com/
3.3EJS初体验
下载安装ejs
npm i ejs --save
实例代码1
<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构

实例代码2
列表渲染
<% code %> 执行JS代码

3.4在express中使用ejs

04express-generator
安装
npm i -g express-generator
创建
express -e 文件名
安装依赖
npm i
运行
npm start
formidable包可以处理文件请求
npm i formidable

05Mongodb
5.1下载与安装
下载链接:https://www.mongodb.com/try/download/community


5.2命令行交互
命令行交互一般是学习数据库的第一步,不过这些命令在后续用的比较少。
数据库命令
1.显示所有的数据库
show dbs
2.切换到指定的数据库,如果数据库不存在会自动创建数据库
use 数据库名
3.显示当前所在的数据库
db
4.删除当前数据库
use 库名
db.dropDataBase()
集合命令
1.创建集合
db.createCollection('集合名称')
2.显示当前数据库中的所有集合
show collections
3.删除某个集合
db.集合名.drop()
4.重命名集合
db.集合名.renameCollection('newname')
文档命令
1.插入文档
db.集合名.insert(文档对象)
db.集合名.insert({name:'张三'},{age:18})
2.查询文档
db.集合名.find(查询条件)
3.更新文档
db.集合名.update(查询条件,新的文档)
db.集合名.update({name:'张三'},{$set:{age:19}})
4.删除文档
db.集合名.remove(查询条件)
_id 是 mongodb 自动生成的唯一编号,用来唯一标识文档
5.3Mongoose
5.3.1介绍
Mongoose 是一个对象文档模型库,官网http://www.mongoosejs.net/
5.3.2作用
方便使用代码操作 mongodb 数据库
5.3.3使用流程
安装Mongoose
npm i mongoose
//1. 安装 mongoose
//2. 导入 mongoose
const mongoose = require('mongoose');
//3. 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/bilibili');
//4. 设置连接回调
//连接成功
mongoose.connection.on('open', () => {
console.log('连接成功');
//5. 创建文档结构对象
let BookSchema = new mongoose.Schema({
//title、author、price均为字段
title: {
type: String,
required: true // 设置必填项
},
author: String,
price: Number
});
//6. 创建文档模型对象(相当于创建book表)
let BookModel = mongoose.model('book', BookSchema);
//7. 插入文档
BookModel.create({
title: '西游记',
author: '吴承恩',
price: 19.9
}, (err, data) => {
if (err) throw err;
//输出 data 对象
console.log(data);
//8. 断开连接
mongoose.disconnect();
});
});
//连接出错
mongoose.connection.on('error', () => {
console.log('连接出错~~');
})
//连接关闭
mongoose.connection.on('close', () => {
console.log('连接关闭');
})
5.3.4字段类型
| 类型 | 描述 |
|---|---|
| String | 字符串 |
| Number | 数字 |
| Boolean | 布尔值 |
| Array | 数组,也可以使用 [] 来标识 |
| Date | 日期 |
| Buffer | Buffer 对象 |
| Mixed | 任意类型,需要使用 mongoose.Schema.Types.Mixed 指定 |
| ObjectId | 对象 ID,需要使用 mongoose.Schema.Types.ObjectId 指定 |
| Decimal128 | 高精度数字,需要使用 mongoose.Schema.Types.Decimal128 指定 |
5.3.5字段值验证
Mongoose 有一些内建验证器,可以对字段值进行验证
必填项
title: {
type: String,
required: true // 设置必填项
},
默认值
author: {
type: String,
default: '匿名' //默认值
},
枚举值
gender: {
type: String,
enum: ['男','女'] //设置的值必须是数组中的
},
唯一值
username: {
type: String,
unique: true
},
unique 需要 重建集合 才能有效果
5.3.6CURD
增删改查
增加
插入一条
SongModel.create({
title:'给我一首歌的时间',
author: 'Jay'
}, function(err, data){
//错误
console.log(err);
//插入后的数据对象
console.log(data);
});
批量插入
//1.引入mongoose
const mongoose = require('mongoose');
//2.链接mongodb数据库 connect 连接
mongoose.connect('mongodb://127.0.0.1:27017/project');
//3.设置连接的回调
mongoose.connection.on('open',()=>{
//4.声明文档结构
const PhoneSchema = new mongoose.Schema({
brand:String,
color:String,
price:Number,
tags:Array
})
//5.创建模型对象
const PhoneModel = mongoose.model('phone',PhoneSchema);
PhoneModel.insertMany([
{
brand:'华为',
color:'灰色',
price:2399,
tags:['电量大','屏幕大','信号好']
},
{
brand:'小米',
color:'白色',
price:2099,
tags:['电量大','屏幕大','信号好']
}
],(err,data)=>{
if(err) throw err;
console.log('写入成功');
mongoose.connection.close();
})
})
删除
删除一条数据
SongModel.deleteOne({_id:'5dd65f32be6401035cb5b1ed'}, function(err){
if(err) throw err;
console.log('删除成功');
mongoose.connection.close();
});
批量删除
SongModel.deleteMany({author:'Jay'}, function(err){
if(err) throw err;
console.log('删除成功');
mongoose.connection.close();
});
更新
更新一条数据
SongModel.updateOne({author: 'JJ Lin'}, {author: '林俊杰'}, function (err) {
if(err) throw err;
mongoose.connection.close();
});
批量更新数据
SongModel.updateMany({author: 'Leehom Wang'}, {author: '王力宏'}, function (err) {
if(err) throw err;
mongoose.connection.close();
});
查询
查询一条数据
SongModel.findOne({author: '王力宏'}, function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
//根据 id 查询数据
SongModel.findById('5dd662b5381fc316b44ce167',function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
批量查询数据
//不加条件查询
SongModel.find(function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
//加条件查询
SongModel.find({author: '王力宏'}, function(err, data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
5.3.7条件控制
运算符
在 mongodb 不能 > < >= <= !== 等运算符,需要使用替代符号
· > 使用 $gt
· < 使用 $lt
· >= 使用 $gte
· <= 使用 $lte
· !== 使用 $ne
db.students.find({id:{$gt:3}}); id号比3大的所有的记录
5.3.8逻辑运算
逻辑或 $or
db.students.find({$or:[{age:18},{age:24}]});
逻辑与 $and
db.students.find({$and: [{age: {$lt:20}}, {age: {$gt: 15}}]});
正则匹配
条件中可以直接使用 JS 的正则语法,通过正则可以进行模糊查询
db.students.find({name:/imissyou/});
5.3.9个性化读取
字段筛选
//0:不要的字段
//1:要的字段
SongModel.find().select({_id:0,title:1}).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
数据排序
//sort 排序
//1:升序
//-1:倒序
SongModel.find().sort({hot:1}).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
数据截取
//skip(n) 跳过n条数据 limit(n)限定几条数据
SongModel.find().skip(10).limit(10).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});

被折叠的 条评论
为什么被折叠?



