# nodejs **Repository Path**: This-wang/nodejs ## Basic Information - **Project Name**: nodejs - **Description**: Node.js零基础视频教程,nodejs新手到高手 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: https://www.bilibili.com/video/BV1gM411W7ex/?p=1&spm_id_from=pageDriver&vd_source=353e8b0a2cae8e4403f67e77ce2a4fe2 - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-11-08 - **Last Updated**: 2025-11-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # nodejs新手到高手 *** ## 目录 - [nodejs新手到高手](#nodejs新手到高手) - [目录](#目录) - [01.Buffer](#01buffer) - [1. 概念](#1-概念) - [2. 特点](#2-特点) - [3. 使用](#3-使用) - [3-1. 创建 Buffer](#3-1-创建-buffer) - [3-2 Buffer 与字符串的转化](#3-2-buffer-与字符串的转化) - [3-3 Buffer 的读写](#3-3-buffer-的读写) - [02.fs模块](#02fs模块) - [一、文件写入](#一文件写入) - [1-1. writeFile 异步写入](#1-1-writefile-异步写入) - [1-2. writeFileSync 同步写入](#1-2-writefilesync-同步写入) - [1-3. appendFile / appendFileSync 追加写入](#1-3-appendfile--appendfilesync-追加写入) - [1-4. createWriteStream 流式写入](#1-4-createwritestream-流式写入) - [二、文件读取](#二文件读取) - [2-1 readFile 异步读取](#2-1-readfile-异步读取) - [2-2 readFileSync 同步读取](#2-2-readfilesync-同步读取) - [2-3 createReadStream 流式读取](#2-3-createreadstream-流式读取) - [2-4 读取文件应用场景](#2-4-读取文件应用场景) - [三、文件移动与重命名](#三文件移动与重命名) - [四、文件删除](#四文件删除) - [五、文件夹操作](#五文件夹操作) - [5-1 mkdir 创建文件夹](#5-1-mkdir-创建文件夹) - [5-2 readdir 读取文件夹](#5-2-readdir-读取文件夹) - [5-3 rmdir 删除文件夹](#5-3-rmdir-删除文件夹) - [六、查看资源状态](#六查看资源状态) - [七、相对路径问题](#七相对路径问题) - [八、\_\_dirname](#八__dirname) - [九、练习](#九练习) - [03.path模块](#03path模块) - [04.HTTP 协议](#04http-协议) - [一、概念](#一概念) - [二、请求报文的组成](#二请求报文的组成) - [三、HTTP 的请求行](#三http-的请求行) - [四、HTTP 请求头](#四http-请求头) - [五、HTTP 的请求体](#五http-的请求体) - [六、响应报文的组成](#六响应报文的组成) - [七、创建 HTTP 服务](#七创建-http-服务) - [7.1 操作步骤](#71-操作步骤) - [7.2 测试](#72-测试) - [7.3 注意事项](#73-注意事项) - [八、浏览器查看 HTTP 报文](#八浏览器查看-http-报文) - [8.1 查看请求行与请求头](#81-查看请求行与请求头) - [8.2 查看请求体](#82-查看请求体) - [8.3 查看 URL 查询字符串](#83-查看-url-查询字符串) - [8.4 查看响应行与响应头](#84-查看响应行与响应头) - [8.5 查看响应体](#85-查看响应体) - [九、获取 HTTP 请求报文](#九获取-http-请求报文) - [9.1 练习](#91-练习) - [十、设置 HTTP 响应报文](#十设置-http-响应报文) - [10.1 练习](#101-练习) - [十一、网页资源的基本加载过程](#十一网页资源的基本加载过程) - [十二、静态资源服务](#十二静态资源服务) - [12.1 网站根目录或静态资源目录](#121-网站根目录或静态资源目录) - [12.2 网页中的 URL](#122-网页中的-url) - [12.2.1 绝对路径](#1221-绝对路径) - [12.2.2 相对路径](#1222-相对路径) - [12.2.3 网页中使用 URL 的场景小结](#1223-网页中使用-url-的场景小结) - [12.3 设置资源类型(mime类型)](#123-设置资源类型mime类型) - [12.4 GET 和 POST 请求场景小结](#124-get-和-post-请求场景小结) - [十三、GET和POST请求的区别](#十三get和post请求的区别) - [05.Node.js 模块化](#05nodejs-模块化) - [一、介绍](#一介绍) - [1.1 什么是模块化与模块 ?](#11-什么是模块化与模块-) - [1.2 什么是模块化项目 ?](#12-什么是模块化项目-) - [1.3 模块化好处](#13-模块化好处) - [二、模块暴露数据](#二模块暴露数据) - [2.1 模块初体验](#21-模块初体验) - [2.2 暴露数据](#22-暴露数据) - [三、导入(引入)模块](#三导入引入模块) - [四、导入模块的基本流程](#四导入模块的基本流程) - [五、CommonJS 规范](#五commonjs-规范) - [06.包管理工具](#06包管理工具) - [一、概念介绍](#一概念介绍) - [1.1 包是什么](#11-包是什么) - [1.2 包管理工具](#12-包管理工具) - [1.3 常用的包管理工具](#13-常用的包管理工具) - [二、npm](#二npm) - [2.1 npm 的安装](#21-npm-的安装) - [2.2 npm 基本使用](#22-npm-基本使用) - [2.2.1 初始化](#221-初始化) - [2.2.2 搜索包](#222-搜索包) - [2.2.3 下载安装包](#223-下载安装包) - [2.2.4 require 导入 npm 包基本流程](#224-require-导入-npm-包基本流程) - [2.3 生产环境与开发环境](#23-生产环境与开发环境) - [2.4 生产依赖与开发依赖](#24-生产依赖与开发依赖) - [2.5 全局安装](#25-全局安装) - [2.5.1 修改 windows 执行策略](#251-修改-windows-执行策略) - [2.5.2 环境变量 Path](#252-环境变量-path) - [2.6 安装包依赖](#26-安装包依赖) - [2.7 安装指定版本的包](#27-安装指定版本的包) - [2.8 删除依赖](#28-删除依赖) - [2.9 配置命令别名](#29-配置命令别名) - [三、cnpm](#三cnpm) - [3.1 介绍](#31-介绍) - [3.2 安装](#32-安装) - [3.3 操作命令](#33-操作命令) - [3.4 npm 配置淘宝镜像](#34-npm-配置淘宝镜像) - [3.4.1 直接配置](#341-直接配置) - [3.4.2 工具配置](#342-工具配置) - [四、yarn](#四yarn) - [4.1 yarn 介绍](#41-yarn-介绍) - [4.2 yarn 特点](#42-yarn-特点) - [4.3 yarn 安装](#43-yarn-安装) - [4.4 yarn 常用命令](#44-yarn-常用命令) - [4.5 yarn 配置淘宝镜像](#45-yarn-配置淘宝镜像) - [4.6 npm 和 yarn 选择](#46-npm-和-yarn-选择) - [五、管理发布包](#五管理发布包) - [5.1 创建与发布](#51-创建与发布) - [5.2 更新包](#52-更新包) - [5.3 删除包](#53-删除包) - [六、扩展内容](#六扩展内容) - [07.NVM](#07nvm) - [一、介绍](#一介绍-1) - [二、使用](#二使用) - [2.1 下载安装](#21-下载安装) - [2.2 常用命令](#22-常用命令) - [08.Express](#08express) - [一、express 介绍](#一express-介绍) - [二、express 使用](#二express-使用) - [2.1 express 下载](#21-express-下载) - [2.2 express 初体验](#22-express-初体验) - [三、express 路由](#三express-路由) - [3.1 什么是路由](#31-什么是路由) - [3.2 路由的使用](#32-路由的使用) - [3.3 获取请求参数](#33-获取请求参数) - [3.4 获取路由参数](#34-获取路由参数) - [四、express 响应设置](#四express-响应设置) - [五、express 中间件](#五express-中间件) - [5.1 什么是中间件](#51-什么是中间件) - [5.2 中间件的作用](#52-中间件的作用) - [5.3 中间件的类型](#53-中间件的类型) - [5.3.1 定义全局中间件](#531-定义全局中间件) - [5.3.2 多个全局中间件](#532-多个全局中间件) - [5.3.3 定义路由中间件](#533-定义路由中间件) - [5.4 静态资源中间件](#54-静态资源中间件) - [5.5 获取请求体数据 body-parser](#55-获取请求体数据-body-parser) - [六、Router](#六router) - [6.1 什么是 Router](#61-什么是-router) - [6.2 Router 作用](#62-router-作用) - [6.3 Router 使用](#63-router-使用) - [七、EJS 模板引擎](#七ejs-模板引擎) - [7.1 什么是模板引擎](#71-什么是模板引擎) - [7.2 什么是 EJS](#72-什么是-ejs) - [7.3 EJS 初体验](#73-ejs-初体验) - [7.4 EJS 常用语法](#74-ejs-常用语法) - [09.MongoDB](#09mongodb) - [一、简介](#一简介) - [1.1 Mongodb 是什么](#11-mongodb-是什么) - [1.2 数据库是什么](#12-数据库是什么) - [1.3 数据库的作用](#13-数据库的作用) - [1.4 数据库管理数据的特点](#14-数据库管理数据的特点) - [1.5 为什么选择 Mongodb](#15-为什么选择-mongodb) - [二、核心概念](#二核心概念) - [三、下载安装与启动](#三下载安装与启动) - [四、命令行交互](#四命令行交互) - [4.1 数据库命令](#41-数据库命令) - [4.2 集合命令](#42-集合命令) - [4.3 文档命令](#43-文档命令) - [4.4 应用场景](#44-应用场景) - [4.4.1 新增](#441-新增) - [4.4.2 删除](#442-删除) - [4.4.3 更新](#443-更新) - [4.4.4 查询](#444-查询) - [五、Mongoose](#五mongoose) - [5.1 介绍](#51-介绍) - [5.2 作用](#52-作用) - [5.3 使用流程](#53-使用流程) - [5.4 字段类型](#54-字段类型) - [5.5 字段值验证](#55-字段值验证) - [5.5.1 必填项](#551-必填项) - [5.5.2 默认值](#552-默认值) - [5.5.3 枚举值](#553-枚举值) - [5.5.4 唯一值](#554-唯一值) - [5.6 CURD](#56-curd) - [5.6.1 增加](#561-增加) - [5.6.2 删除](#562-删除) - [5.6.3 更新](#563-更新) - [5.6.4 查询](#564-查询) - [5.7 条件控制](#57-条件控制) - [5.7.1 运算符](#571-运算符) - [5.7.2 逻辑运算](#572-逻辑运算) - [5.7.3 正则匹配](#573-正则匹配) - [5.8 个性化读取](#58-个性化读取) - [5.8.1 字段筛选](#581-字段筛选) - [5.8.2 数据排序](#582-数据排序) - [5.8.3 数据截取](#583-数据截取) - [六、 图形化管理工具](#六-图形化管理工具) - [10.接口](#10接口) - [一、简介](#一简介-1) - [1.1 接口是什么](#11-接口是什么) - [1.2 接口的作用](#12-接口的作用) - [1.3 接口的开发与调用](#13-接口的开发与调用) - [1.4 接口的组成](#14-接口的组成) - [二、RESTful API](#二restful-api) - [三、json-server](#三json-server) - [四、接口测试工具](#四接口测试工具) - [11.会话控制](#11会话控制) - [一、介绍](#一介绍-2) - [二、cookie](#二cookie) - [2.1 cookie 是什么](#21-cookie-是什么) - [2.2 cookie 的特点](#22-cookie-的特点) - [2.3 cookie 的运行流程](#23-cookie-的运行流程) - [2.4 浏览器操作 cookie](#24-浏览器操作-cookie) - [2.5 cookie 的代码操作](#25-cookie-的代码操作) - [三、session](#三session) - [3.1 session 是什么](#31-session-是什么) - [3.2 session 的作用](#32-session-的作用) - [3.3 session 运行流程](#33-session-运行流程) - [3.4 session 的代码操作](#34-session-的代码操作) - [四、session 和 cookie 的区别](#四session-和-cookie-的区别) - [五、token](#五token) - [5.1 token 是什么](#51-token-是什么) - [5.2 token 的作用](#52-token-的作用) - [5.3 token 的工作流程](#53-token-的工作流程) - [5.4 token 的特点](#54-token-的特点) - [5.5 JWT](#55-jwt) - [六、附录](#六附录) - [6.1 本地域名](#61-本地域名) - [6.1.1 操作流程](#611-操作流程) - [6.1.2 原理](#612-原理) *** ## 01.Buffer *** ### 1. 概念 **Buffer 是一个类似于数组的 对象 ,用于表示固定长度的字节序列** **Buffer 本质是一段内存空间,专门用来处理 二进制数据 。**
1
*** ### 2. 特点 1. Buffer 大小固定且无法调整 2. Buffer 性能较好,可以直接对计算机内存进行操作 3. 每个元素的大小为 1 字节(byte)
2
*** ### 3. 使用 #### 3-1. 创建 Buffer Node.js 中创建 Buffer 的方式主要如下几种: 1.Buffer.alloc ```javascript //创建了一个长度为 10 字节的 Buffer,相当于申请了 10 字节的内存空间,每个字节的值为 0 let buf_1 = Buffer.alloc(10); // 结果为 ``` 2.Buffer.allocUnsafe ```javascript //创建了一个长度为 10 字节的 Buffer,buffer 中可能存在旧的数据, 可能会影响执行结果,所以叫unsafe let buf_2 = Buffer.allocUnsafe(10); ``` 3.Buffer.from ```javascript //通过字符串创建 Buffer let buf_3 = Buffer.from('hello'); //通过数组创建 Buffer let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]); ``` #### 3-2 Buffer 与字符串的转化 我们可以借助 `toString` 方法将 Buffer 转为字符串 ```javascript let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]); console.log(buf_4.toString()) ``` > toString 默认是按照 `utf-8` 编码方式进行转换的。 #### 3-3 Buffer 的读写 Buffer 可以直接通过 `[]` 的方式对数据进行处理。 ```javascript //读取 console.log(buf_3[1]); //修改 buf_3[1] = 97; //查看字符串结果 console.log(buf_3.toString()); ``` > 注意: > > 1. 如果修改的数值超过 255 ,则超过 8 位数据会被舍弃 > 2. 一个 utf-8 的字符 一般 占 3 个字节 *** ## 02.fs模块 *** fs 全称为 `file system` ,称之为 `文件系统` ,是 Node.js 中的 内置模块 ,可以对计算机中的磁盘进行操 作。 本章节会介绍如下几个操作: 1. 文件写入 2. 文件读取 3. 文件移动与重命名 4. 文件删除 5. 文件夹操作 6. 查看资源状态 *** ### 一、文件写入 文件写入就是将 `数据` 保存到 `文件` 中,我们可以使用如下几个方法来实现该效果 |方法 |说明 | |---|---| |writeFile |异步写入 | |writeSync |同步写入 | |appendFile/appendFileSync |追加写入 | |createWriteStream |流式写入 | #### 1-1. writeFile 异步写入 语法: `fs.writeFile(file, data[, options], callback)` 参数说明: - file 文件名 - data 待写入的数据 - options 选项设置 `(可选)` - callback 写入回调 返回值: `undefined` 代码示例: ```javascript // require 是 Node.js 环境中的'全局'变量,用来导入模块 const fs = require('fs'); //将 『三人行,必有我师焉。』 写入到当前文件夹下的『座右铭.txt』文件中 fs.writeFile('./座右铭.txt', '三人行,必有我师焉。', err => { //如果写入失败,则回调函数调用时,会传入错误对象,如写入成功,会传入 null if(err){ console.log(err); return; } console.log('写入成功'); }); ``` #### 1-2. writeFileSync 同步写入 语法: `fs.writeFileSync(file, data[, options])` 参数与 fs.writeFile 大体一致,只是没有 callback 参数 返回值: `undefined` 代码示例: ```javascript try{ fs.writeFileSync('./座右铭.txt', '三人行,必有我师焉。'); }catch(e){ console.log(e); } ``` > Node.js 中的磁盘操作是由其他 `线程` 完成的,结果的处理有两种模式: > > - 同步处理 JavaScript 主线程 `会等待` 其他线程的执行结果,然后再继续执行主线程的代码,`效率较低` > -异步处理 JavaScript 主线程 `不会等待` 其他线程的执行结果,直接执行后续的主线程代码,`效率较好` #### 1-3. appendFile / appendFileSync 追加写入 appendFile 作用是在文件尾部追加内容,appendFile 语法与 writeFile 语法完全相同 语法: `fs.appendFile(file, data[, options], callback)` `fs.appendFileSync(file, data[, options])` 返回值: 二者都为 `undefined` 实例代码: ```javascript fs.appendFile('./座右铭.txt','择其善者而从之,其不善者而改之。', err => { if(err) throw err; console.log('追加成功') }); fs.appendFileSync('./座右铭.txt','\r\n温故而知新, 可以为师矣'); ``` #### 1-4. createWriteStream 流式写入 语法: `fs.createWriteStream(path[, options])` 参数说明: path 文件路径 options 选项配置( `可选` ) 返回值: `Object` 代码示例: ```javascript let ws = fs.createWriteStream('./观书有感.txt'); ws.write('半亩方塘一鉴开\r\n'); ws.write('天光云影共徘徊\r\n'); ws.write('问渠那得清如许\r\n'); ws.write('为有源头活水来\r\n'); ws.end(); ``` > `程序打开一个文件是需要消耗资源的` ,流式写入可以减少打开关闭文件的次数。 > 流式写入方式适用于 `大文件写入或者频繁写入` 的场景, writeFile 适合于 `写入频率较低的场景` *** ### 二、文件读取 文件读取顾名思义,就是通过程序从文件中取出其中的数据,我们可以使用如下几种方式: | 方法 | 说明 | |---|---| |readFile | 异步读取 | |readFileSync | 同步读取 | |createReadStream | 流式读取 | #### 2-1 readFile 异步读取 语法: `fs.readFile(path[, options], callback)` 参数说明: - path 文件路径 - options 选项配置 - callback 回调函数 返回值: undefined 代码示例: ```javascript //导入 fs 模块 const fs = require('fs'); fs.readFile('./座右铭.txt', (err, data) => { if(err) throw err; console.log(data); }); fs.readFile('./座右铭.txt', 'utf-8',(err, data) => { if(err) throw err; console.log(data); }); ``` #### 2-2 readFileSync 同步读取 语法: `fs.readFileSync(path[, options])` 参数说明: - path 文件路径 - options 选项配置 返回值: `string | Buffer` 代码示例: ```javascript let data = fs.readFileSync('./座右铭.txt'); let data2 = fs.readFileSync('./座右铭.txt', 'utf-8'); ``` #### 2-3 createReadStream 流式读取 语法: `fs.createReadStream(path[, options])` 参数说明: - path 文件路径 - options 选项配置( `可选` ) 返回值: `Object` 代码示例: ```javascript //创建读取流对象 let rs = fs.createReadStream('./观书有感.txt'); //每次取出 64k 数据后执行一次 data 回调 rs.on('data', data => { console.log(data); console.log(data.length); }); //读取完毕后, 执行 end 回调 rs.on('end', () => { console.log('读取完成') }) fs.rename('./观书有感.txt', './论语/观书有感.txt', (err) =>{ if(err) throw err; console.log('移动完成') }); fs.renameSync('./座右铭.txt', './论语/我的座右铭.txt'); ``` #### 2-4 读取文件应用场景 - 电脑开机 - 程序运行 - 编辑器打开文件 - 查看图片 - 播放视频 - 播放音乐 - Git 查看日志 - 上传文件 - 查看聊天记录 *** ### 三、文件移动与重命名 在 Node.js 中,我们可以使用 `rename` 或 `renameSync` 来移动或重命名 `文件或文件夹` 语法: `fs.rename(oldPath, newPath, callback)` `fs.renameSync(oldPath, newPath)` 参数说明: - oldPath 文件当前的路径 - newPath 文件新的路径 - callback 操作后的回调 代码示例: ```javascript fs.rename('./观书有感.txt', './论语/观书有感.txt', (err) =>{ if(err) throw err; console.log('移动完成') }); fs.renameSync('./座右铭.txt', './论语/我的座右铭.txt'); ``` *** ### 四、文件删除 在 Node.js 中,我们可以使用 `unlink` 或 `unlinkSync` 来删除文件 语法: `fs.unlink(path, callback)` `fs.unlinkSync(path)` 参数说明: - path 文件路径 - callback 操作后的回调 代码示例: ```javascript const fs = require('fs'); fs.unlink('./test.txt', err => { if(err) throw err; console.log('删除成功'); }); fs.unlinkSync('./test2.txt'); ``` *** ### 五、文件夹操作 借助 Node.js 的能力,我们可以对文件夹进行 `创建` 、 `读取` 、 `删除` 等操作 | 方法 | 说明 | |---|---| |mkdir / mkdirSync |创建文件夹 | |readdir / readdirSync |读取文件夹 | |rmdir / rmdirSync |删除文件夹 | #### 5-1 mkdir 创建文件夹 在 Node.js 中,我们可以使用 `mkdir` 或 `mkdirSync` 来创建文件夹 语法: `fs.mkdir(path[, options], callback)` `fs.mkdirSync(path[, options])` 参数说明: - path 文件夹路径 - options 选项配置( `可选` ) - callback 操作后的回调 示例代码: ```javascript //异步创建文件夹 fs.mkdir('./page', err => { if(err) throw err; console.log('创建成功'); }); //递归异步创建 fs.mkdir('./1/2/3', {recursive: true}, err => { if(err) throw err; console.log('递归创建成功'); }); //递归同步创建文件夹 fs.mkdirSync('./x/y/z', {recursive: true}); ``` #### 5-2 readdir 读取文件夹 在 Node.js 中,我们可以使用 `readdir` 或 `readdirSync` 来读取文件夹 语法: `fs.readdir(path[, options], callback)` `fs.readdirSync(path[, options])` 参数说明: - path 文件夹路径 - options 选项配置( 可选 ) - callback 操作后的回调 示例代码: ```javascript //异步读取 fs.readdir('./论语', (err, data) => { if(err) throw err; console.log(data); }); //同步读取 let data = fs.readdirSync('./论语'); console.log(data); ``` #### 5-3 rmdir 删除文件夹 在 Node.js 中,我们可以使用 `rmdir` 或 `rmdirSync` 来删除文件夹 语法: `fs.rmdir(path[, options], callback)` `fs.rmdirSync(path[, options])` 参数说明: - path 文件夹路径 - options 选项配置( 可选 ) - callback 操作后的回调 示例代码: ```javascript //异步删除文件夹 fs.rmdir('./page', err => { if(err) throw err; console.log('删除成功'); }); //异步递归删除文件夹 fs.rmdir('./1', {recursive: true}, err => { if(err) { console.log(err); } console.log('递归删除') }); //同步递归删除文件夹 fs.rmdirSync('./x', {recursive: true}) ``` *** ### 六、查看资源状态 在 `Node.js` 中,我们可以使用 `stat` 或 `statSync` 来查看资源的详细信息 语法: `fs.stat(path[, options], callback)` `fs.statSync(path[, options])` 参数说明: - path 文件夹路径 - options 选项配置( 可选 ) - callback 操作后的回调 示例代码: ```javascript //异步获取状态 fs.stat('./data.txt', (err, data) => { if(err) throw err; console.log(data); }); //同步获取状态 let data = fs.statSync('./data.txt'); ``` 结果值对象结构: - size 文件体积 - birthtime 创建时间 - mtime 最后修改时间 - isFile 检测是否为文件 - isDirectory 检测是否为文件夹 - .... *** ### 七、相对路径问题 fs 模块对资源进行操作时,路径的写法有两种: - 相对路径 - ./座右铭.txt 当前目录下的座右铭.txt - 座右铭.txt 等效于上面的写法 - ../座右铭.txt 当前目录的上一级目录中的座右铭.txt - 绝对路径 - D:/Program Files windows 系统下的绝对路径 - /usr/bin Linux 系统下的绝对路径 > 相对路径中所谓的 当前目录 ,指的是 命令行的工作目录 ,而并非是文件的所在目录 > 所以当命令行的工作目录与文件所在目录不一致时,会出现一些 BUG *** ### 八、__dirname `__dirname` 与 `require` 类似,都是 Node.js 环境中的'全局'变量 `__dirname` 保存着 `当前文件所在目录的绝对路径` ,可以使用__dirname 与文件名拼接成绝对路径 代码示例: ```javascript let data = fs.readFileSync(__dirname + '/data.txt'); console.log(data); ``` > 使用 fs 模块的时候,尽量使用__dirname 将路径转化为绝对路径,这样可以避免相对路径产生的 Bug *** ### 九、练习 1. 编写一个 JS 文件,实现复制文件的功能 2. 文件重命名 *** ## 03.path模块 *** path 模块提供了 `操作路径` 的功能,我们将介绍如下几个较为常用的几个 API: |API |说明 | |---|---| |path.resolve | 拼接规范的绝对路径 `常用` | |path.sep |获取操作系统的路径分隔符 | |path.parse |解析路径并返回对象 | |path.basename |获取路径的基础名称 | |path.dirname |获取路径的目录名 | |path.extname |获得路径的扩展名 | 代码示例: ```javascript const path = require('path'); //获取路径分隔符 console.log(path.sep); //拼接绝对路径 console.log(path.resolve(__dirname, 'test')); //解析路径 let pathname = 'D:/program file/nodejs/node.exe'; console.log(path.parse(pathname)); //获取路径基础名称 console.log(path.basename(pathname)) //获取路径的目录名 console.log(path.dirname(pathname)); //获取路径的扩展名 console.log(path.extname(pathname)); ``` *** ## 04.HTTP 协议 *** ### 一、概念 HTTP(hypertext transport protocol)协议;中文叫**超文本传输协议** 是一种基于TCP/IP的应用层通信协议 这个协议详细规定了 `浏览器` 和万维网 `服务器` 之间互相通信的规则。 协议中主要规定了两个方面的内容 - 客户端:用来向服务器发送数据,可以被称之为**请求报文** - 服务端:向客户端返回数据,可以被称之为**响应报文** > 报文:可以简单理解为就是一堆字符串 ### 二、请求报文的组成 - 请求行 - 请求头 - 空行 - 请求体 *** ### 三、HTTP 的请求行 - 请求方法(get、post、put、delete等) - 请求 URL(统一资源定位器) 例如: - http: 协议(https、ftp、ssh等) - www.baidu.com 域名 - 80 端口号 - /index.html 路径 - a=100&b=200 查询字符串 - \# logo 哈希(锚点链接) - HTTP协议版本号 *** ### 四、HTTP 请求头 格式:『头名:头值』 常见的请求头有: |请求头|解释| |---|---| |Host|主机名| |Connection|连接的设置 keep-alive(保持连接);close(关闭连接)| |Cache-Control|缓存控制 max-age = 0 (没有缓存)| |Upgrade-Insecure-Requests|将网页中的http请求转化为https请求(很少用)老网站升级| |User-Agent|用户代理,客户端字符串标识,服务器可以通过这个标识来识别这个请求来自哪个客户端 ,一般在PC端和手机端的区分| |Accept|设置浏览器接收的数据类型| |Accept-Encoding|设置接收的压缩方式| |Accept-Language|设置接收的语言 q=0.7 为喜好系数,满分为1| |Cookie|后面单独讲| *** ### 五、HTTP 的请求体 请求体内容的格式是非常灵活的, (可以是空)\==> GET请求, (也可以是字符串,还可以是JSON)===> POST请求 例如: - 字符串:keywords=手机&price=2000 - JSON:{"keywords":"手机","price":2000} *** ### 六、响应报文的组成 - 响应行 > HTTP/1.1 200 OK - HTTP/1.1:HTTP协议版本号 - 200:响应状态码 404 Not Found 500 Internal Server Error 还有一些状态码,参考: - OK:响应状态描述 > 响应状态码和响应字符串关系是一一对应的。 - 响应头 > Cache-Control:缓存控制 private 私有的,只允许客户端缓存数据 > Connection 链接设置 > Content-Type:text/html;charset=utf-8 设置响应体的数据类型以及字符集,响应体为html,字符集utf-8 > Content-Length:响应体的长度,单位为字节 - 空行 - 响应体 响应体内容的类型是非常灵活的,常见的类型有 HTML、CSS、JS、图片、JSON *** ### 七、创建 HTTP 服务 使用 nodejs 创建 HTTP 服务 #### 7.1 操作步骤 ```javascript //1. 导入 http 模块 const http = require('http'); //2. 创建服务对象 create 创建 server 服务 // request 意为请求. 是对请求报文的封装对象, 通过 request 对象可以获得请求报文的数据 // response 意为响应. 是对响应报文的封装对象, 通过 response 对象可以设置响应报文 const server = http.createServer((request, response) => { response.end('Hello HTTP server'); }); //3. 监听端口, 启动服务 server.listen(9000, () => { console.log('服务已经启动, 端口 9000 监听中...'); }); ``` > http.createServer 里的回调函数的执行时机: 当接收到 HTTP 请求的时候,就会执行 #### 7.2 测试 浏览器请求对应端口 > #### 7.3 注意事项 1. 命令行 `ctrl + c` 停止服务 2. 当服务启动后,更新代码 `必须重启服务才能生效` 3. 响应内容中文乱码的解决办法 ```javascript response.setHeader('content-type','text/html;charset=utf-8'); ``` 4. 端口号被占用 ```shell Error: listen EADDRINUSE: address already in use :::9000 ``` 1)关闭当前正在运行监听端口的服务 ( 使用较多 ) 2)修改其他端口号 5. HTTP 协议默认端口是 80 。HTTPS 协议的默认端口是 443, HTTP 服务开发常用端口有 3000, 8080,8090,9000 等 > 如果端口被其他程序占用,可以使用 资源监视器 找到占用端口的程序,然后使用 任务管理器对应的程序 *** ### 八、浏览器查看 HTTP 报文 点击步骤
1
#### 8.1 查看请求行与请求头
2
#### 8.2 查看请求体
3
#### 8.3 查看 URL 查询字符串
4
#### 8.4 查看响应行与响应头
5
#### 8.5 查看响应体
6
*** ### 九、获取 HTTP 请求报文 想要获取请求的数据,需要通过 `request` 对象 |含义|语法|重点掌握| |---|---|---| |请求方法|request.method|*| |请求版本|request.httpVersion|| |请求路径|request.url|*| |URL路径|require('url').parse(request.url).pathname|*| |URL 查询字符串|require('url').parse(request.url, true).query|*| |请求头|request.headers|*| |请求体|request.on('data', function(chunk){}) request.on('end', function(){})|*| 注意事项: 1. request.url 只能获取路径以及查询字符串,无法获取 URL 中的域名以及协议的内容 2. request.headers 将请求信息转化成一个对象,并将属性名都转化成了『小写』 3. 关于路径:如果访问网站的时候,只填写了 IP 地址或者是域名信息,此时请求的路径为『 / 』 4. 关于 favicon.ico:这个请求是属于浏览器自动发送的请求 #### 9.1 练习 按照以下要求搭建 HTTP 服务 |请求类型(方法)|请求地址|响应体结果| |---|---|---| |get|/login|登录页面| |get|/reg|注册页面| ```javascript //1、引入http模块 const http = require("http"); //2、建立服务 const server = http.createServer((request,response)=>{ let {url,method} = request; //对象的解构赋值 //设置响应头信息 //解决中文乱码 response.setHeader("Content-Type","text/html;charset=utf-8") if(url == "/register" && method == "GET"){ response.end("注册页面"); }else if(url=="/login" && method == "GET"){ response.end("登录页面"); }else{ response.end("

404 Not Found

") } }) //3、监听端口 server.listen(8000,()=>{ console.log('服务启动中....'); }) ``` *** ### 十、设置 HTTP 响应报文 |作用|语法| |---|---| |设置响应状态码|response.statusCode| |设置响应状态描述|response.statusMessage( `用的非常少` )| |设置响应头信息|response.setHeader('头名', '头值')| |设置响应体|response.write('xx') response.end('xxx')| ```javascript write 和 end 的两种使用情况: //1. write 和 end 的结合使用 响应体相对分散 response.write('xx'); response.write('xx'); response.write('xx'); response.end(); //每一个请求,在处理的时候必须要执行 end 方法的 //2. 单独使用 end 方法 响应体相对集中 response.end('xxx'); ``` #### 10.1 练习 搭建 HTTP 服务,响应一个 4 行 3 列的表格,并且要求表格有 `隔行换色效果` ,且 `点击` 单元格能 `高亮显示` ```javascript //导入 http 模块 const http = require('http'); //创建服务对象 const server = http.createServer((request, response) => { response.end(` Document
`); //设置响应体 }); //监听端口, 启动服务 server.listen(9000, () => { console.log('服务已经启动....') }); ``` *** ### 十一、网页资源的基本加载过程
7
网页资源的加载都是循序渐进的,首先获取 HTML 的内容, 然后解析 HTML 在发送其他资源的请求,如 CSS,Javascript,图片等。 `理解了这个内容对于后续的学习与成长有非常大的帮助` *** ### 十二、静态资源服务 静态资源是指 `内容长时间不发生改变的资源` ,例如图片,视频,CSS 文件,JS文件,HTML文件,字体文件等 动态资源是指 `内容经常更新的资源` ,例如百度首页,网易首页,京东搜索列表页面等 #### 12.1 网站根目录或静态资源目录 HTTP 服务在哪个文件夹中寻找静态资源,那个文件夹就是 `静态资源目录` ,也称之为 `网站根目录` > 思考:vscode 中使用 live-server 访问 HTML 时, 它启动的服务中网站根目录是谁? #### 12.2 网页中的 URL 网页中的 URL 主要分为两大类:相对路径与绝对路径 ##### 12.2.1 绝对路径 绝对路径可靠性强,而且相对容易理解,在项目中运用较多 |形式|特点| |---|---| ||直接向目标资源发送请求,容易理解。网站的外链会用到此形式| |//atguigu.com/web|与页面 URL 的协议拼接形成完整 URL 再发送请求。大型网站用的比较多| |/web|与页面 URL 的协议、主机名、端口拼接形成完整 URL 再发送请求。中小 型网站| ##### 12.2.2 相对路径 相对路径在发送请求时,需要与当前页面 URL 路径进行 `计算` ,得到完整 URL 后,再发送请求,学习阶段用的较多 例如当前网页 url 为 |形式|最终的 URL| |---|---| |./css/app.css|| |js/app.js|| |../img/logo.png|| |../../mp4/show.mp4|| ##### 12.2.3 网页中使用 URL 的场景小结 包括但不限于如下场景: - a 标签 href - link 标签 href - script 标签 src - img 标签 src - video audio 标签 src - form 中的 action - AJAX 请求中的 URL #### 12.3 设置资源类型(mime类型) 媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。 ```txt mime 类型结构: [type]/[subType] 例如: text/html text/css image/jpeg image/png application/json ``` HTTP 服务可以设置响应头 Content-Type 来表明响应体的 MIME 类型,浏览器会根据该类型决定如何处理资源 下面是常见文件对应的 mime 类型 ```txt html: 'text/html', css: 'text/css', js: 'text/javascript', png: 'image/png', jpg: 'image/jpeg', gif: 'image/gif', mp4: 'video/mp4', mp3: 'audio/mpeg', json: 'application/json' ``` > 对于未知的资源类型,可以选择 application/octet-stream 类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的 `下载` 效果 ```javascript require('http').createServer((request,response)=>{ //获取请求的方法已经路径 let {url,method} = request; //判断请求方式以及请求路径 if(method == "GET" && url == "/index.html"){ //需要响应文件中的内容 let data = require('fs').readFileSync(__dirname + '/index.html'); response.end(data); }else if(method == "GET" && url == "/css/app.css"){ //需要响应文件中的内容 let data = require('fs').readFileSync(__dirname + '/public/css/app.css'); response.end(data); }else if(method == "GET" && url == "/js/app.js"){ //需要响应文件中的内容 let data = require('fs').readFileSync(__dirname + '/public/js/app.js'); response.end(data); } else{ //404响应 response.statusCode = 404; response.end("

404 Not Found

"); } }).listen(80,()=>{ console.log('80端口正在启动中....'); }) ``` 很明显上面的代码,当只要有一个请求路径就需要进行判断,显然这种方式不够完美,那么我们需要封装 ```javascript require('http').createServer((request,response)=>{ //获取请求的方法已经路径 let {url,method} = request; //文件夹路径 let rootDir = __dirname + '/public'; //拼接文件路径 let filePath = rootDir + url; //读取文件内容 fs.readFile(filePath,(err,data)=>{ //判断 if(err){ //如果出现错误,响应404状态码 response.statusCode = 404; response.end('

404 Not Found

'); }else{ //响应文件内容 response.end(data); } }) }).listen(80,()=>{ console.log('80端口正在启动中....'); }) ``` #### 12.4 GET 和 POST 请求场景小结 GET 请求的情况: - 在地址栏直接输入 url 访问 - 点击 a 链接 - link 标签引入 css - script 标签引入 js - img 标签引入图片 - form 标签中的 method 为 get (不区分大小写) - ajax 中的 get 请求 POST 请求的情况: - form 标签中的 method 为 post(不区分大小写) - AJAX 的 post 请求 *** ### 十三、GET和POST请求的区别 GET 和 POST 是 HTTP 协议请求的两种方式。 - GET 主要用来获取数据,POST 主要用来提交数据 - GET 带参数请求是将参数缀到 URL 之后,在地址栏中输入 url 访问网站就是 GET 请求, - POST 带参数请求是将参数放到请求体中 - POST 请求相对 GET 安全一些,因为在浏览器中参数会暴露在地址栏 - GET 请求大小有限制,一般为 2K,而 POST 请求则没有大小限制 *** ## 05.Node.js 模块化 *** ### 一、介绍 #### 1.1 什么是模块化与模块 ? 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 `模块化` 其中拆分出的 `每个文件就是一个模块` ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用 #### 1.2 什么是模块化项目 ? 编码时是按照模块一个一个编码的, 整个项目就是一个模块化的项目 #### 1.3 模块化好处 下面是模块化的一些好处: 1. 防止命名冲突 2. 高复用性 3. 高维护性 *** ### 二、模块暴露数据 #### 2.1 模块初体验 可以通过下面的操作步骤,快速体验模块化 1. 创建 `me.js` ```javascript //声明函数 function tiemo(){ console.log('贴膜....'); } //暴露数据 module.exports = tiemo; ``` 2. 创建 index.js ```javascript //导入模块 const tiemo = require('./me.js'); //调用函数 tiemo(); ``` #### 2.2 暴露数据 模块暴露数据的方式有两种: 1. module.exports = value 2. exports.name = value > 使用时有几点注意: > > - module.exports 可以暴露 `任意` 数据 > - 不能使用 `exports = value` 的形式暴露数据,模块内部 module 与 exports 的隐式关系 `exports = module.exports = {}` ,require 返回的是目标模块中 `module.exports` 的值
1
*** ### 三、导入(引入)模块 在模块中使用 require 传入文件路径即可引入文件 > const test = require('./me.js'); require 使用的一些注意事项: 1. 对于自己创建的模块,导入时路径建议写 `相对路径` ,且不能省略 `./` 和 `../` 2. `js` 和 `json` 文件导入时可以不用写后缀,c/c++编写的 `node` 扩展文件也可以不写后缀,但是一般用不到 3. 如果导入其他类型的文件,会以 `js` 文件进行处理 4. 如果导入的路径是个文件夹,则会 `首先` 检测该文件夹下 `package.json` 文件中 `main` 属性对应的文件, 如果存在则导入,反之如果文件不存在会报错。 如果 main 属性不存在,或者 package.json 不存在,则会尝试导入文件夹下的 `index.js` 和`index.json` ,如果还是没找到,就会报错 5. 导入 node.js 内置模块时,直接 require 模块的名字即可,无需加 `./` 和 `../` *** ### 四、导入模块的基本流程 这里我们介绍一下 `require` 导入 `自定义模块` 的基本流程 1. 将相对路径转为绝对路径,定位目标文件 2. 缓存检测 3. 读取目标文件代码 4. 包裹为一个函数并执行(自执行函数)。通过 `arguments.callee.toString()` 查看自执行函数 5. 缓存模块的值 6. 返回 `module.exports` 的值 ```flow st=>start: 开始 op1=>operation: require('./me.js') op2=>operation: 将路径转为绝对路径 op3=>operation: 读取目标文件代码 op4=>operation: 包裹为自执行函数 op5=>operation: 获得 module.exports 的值,缓存模块 op6=>operation: 返回 module.exports condition=>condition: 缓存检测 e=>end: 结束 st->op1->op2->condition condition(no)->op3->op4->op5->op6 condition(yes)->e ``` *** ### 五、CommonJS 规范 module.exports 、 exports 以及 require 这些都是 CommonJS 模块化规范中的内容。 而 Node.js 是实现了 CommonJS 模块化规范,二者关系有点像 JavaScript 与 ECMAScript *** ## 06.包管理工具
1
*** ### 一、概念介绍 #### 1.1 包是什么 『包』英文单词是 `package` ,代表了一组特定功能的源码集合 #### 1.2 包管理工具 管理『包』的应用软件,可以对「包」进行 `下载安装` , `更新` , `删除` , `上传` 等操作 借助包管理工具,可以快速开发项目,提升开发效率 包管理工具是一个通用的概念,很多编程语言都有包管理工具,所以 `掌握好包管理工具非常重要` #### 1.3 常用的包管理工具 下面列举了前端常用的包管理工具 - `npm` - yarn - cnpm *** ### 二、npm npm 全称 `Node Package Manager` ,翻译为中文意思是『Node 的包管理工具』 npm 是 node.js 官方内置的包管理工具,是 `必须要掌握住的工具` #### 2.1 npm 的安装 node.js 在安装时会 `自动安装 npm` ,所以如果你已经安装了 node.js,可以直接使用 npm 可以通过 `npm -v` 查看版本号测试,如果显示版本号说明安装成功,反之安装失败
2
> 查看版本时可能与上图版本号不一样,不过不影响正常使用 #### 2.2 npm 基本使用 ##### 2.2.1 初始化 创建一个空目录,然后以此目录作为工作目录 `启动命令行工具` ,执行 `npm init`
3
`npm init` 命令的作用是将文件夹初始化为一个『包』, `交互式创建 package.json 文件` `package.json` 是包的配置文件,每个包都必须要有 `package.json` `package.json` 内容示例: ```json { "name": "01_npm", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } ``` 属性翻译 ```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 证书功能上是相同的,关于开源证书扩展阅读 > 4. `package.json` 可以手动创建与修改 > 5. 使用 `npm init -y` 或者 `npm init --yes` 极速创建 `package.json` ##### 2.2.2 搜索包 搜索包的方式有两种 1. 命令行 『npm s/search 关键字』 2. `网站搜索` 网址是 > 经常有同学问,『我怎样才能精准找到我需要的包?』 > > 这个事儿需要大家在实践中不断的积累,通过看文章,看项目去学习去积累 ##### 2.2.3 下载安装包 我们可以通过 `npm install` 和 `npm i` 命令安装包 ```shell # 格式 npm install <包名> npm i <包名> # 示例 npm install uniq npm i uniq ``` 运行之后文件夹下会增加两个资源 - `node_modules` 文件夹 存放下载的包 - `package-lock.json` 包的锁文件 ,用来锁定包的版本 > 安装 uniq 之后, uniq 就是当前这个包的一个 `依赖包` ,有时会简称为 `依赖` > > 比如我们创建一个包名字为 A,A 中安装了包名字是 B,我们就说 `B 是 A 的一个依赖包` ,也会说 `A 依赖 B` ##### 2.2.4 require 导入 npm 包基本流程 1. 在当前文件夹下 node_modules 中寻找同名的文件夹 2. 在上级目录中下的 node_modules 中寻找同名的文件夹,直至找到磁盘根目录 #### 2.3 生产环境与开发环境 开发环境是程序员 `专门用来写代码` 的环境,一般是指程序员的电脑,开发环境的项目一般 `只能程序员自己访问` 生产环境是项目 `代码正式运行` 的环境,一般是指正式的服务器电脑,生产环境的项目一般 `每个客户都可以访问` #### 2.4 生产依赖与开发依赖 我们可以在安装时设置选项来区分 `依赖的类型` ,目前分为两类: |类型|命令|补充| |---|---|---| |生产依赖|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.5 全局安装 我们可以执行安装选项 `-g` 进行全局安装 > npm i -g nodemon 全局安装完成之后就可以在命令行的任何位置运行 `nodemon` 命令 该命令的作用是 `自动重启 node 应用程序` > 说明: > > - 全局安装的命令不受工作目录位置影响 > - 可以通过 `npm root -g` 可以查看全局安装包的位置 > - `不是所有的包都适合全局安装` , 只有全局类的工具才适合,可以通过 `查看包的官方文档来确定` > - `安装方式` ,这里先不必太纠结 ##### 2.5.1 修改 windows 执行策略
4
windows 默认不允许 npm 全局命令执行脚本文件,所以需要修改执行策略 1. 以 `管理员身份` 打开 powershell 命令行
5
2. 键入命令 `set-ExecutionPolicy remoteSigned`
6
3. 键入 `A` 然后敲回车 👌 4. 如果不生效,可以尝试重启 vscode ##### 2.5.2 环境变量 Path Path 是操作系统的一个环境变量,可以设置一些文件夹的路径,在当前工作目录下找不到可执行文件时,就会在环境变量 Path 的目录中挨个的查找,如果找到则执行,如果没有找到就会报错
7
> 补充说明: > > - 如果希望某个程序在任何工作目录下都能正常运行,就应该将该程序的所在目录配置到环境变量 Path 中 > - windows 下查找命令的所在位置 > - cmd 命令行 中执行 where nodemon > - powershell命令行 执行 get-command nodemon #### 2.6 安装包依赖 在项目协作中有一个常用的命令就是 `npm i` ,通过该命令可以依据 `package.json` 和 `package-lock.json` 的依赖声明安装项目依赖 ```shell npm i npm install ``` > node_modules 文件夹大多数情况都不会存入版本库 #### 2.7 安装指定版本的包 项目中可能会遇到版本不匹配的情况,有时就需要安装指定版本的包,可以使用下面的命令的 ```shell ## 格式 npm i <包名@版本号> ## 示例 npm i jquery@1.11.2 ``` #### 2.8 删除依赖 项目中可能需要删除某些不需要的包,可以使用下面的命令 ```shell ## 局部删除 npm remove uniq npm r uniq ## 全局删除 npm remove -g nodemon ``` #### 2.9 配置命令别名 通过配置命令别名可以更简单的执行命令 配置 `package.json` 中的 `scripts` 属性 ```json { . . . "scripts": { "server": "node server.js", "start": "node index.js", }, . . } ``` 配置完成之后,可以使用别名执行命令 ```shell npm run server npm run start ``` 不过 start 别名比较特别,使用时可以省略 run ```shell npm start ``` > 补充说明: > > - `npm start` 是项目中常用的一个命令,一般用来启动项目 > - `npm run` 有自动向上级目录查找的特性,跟 `require` 函数也一样 > - 对于陌生的项目,我们可以通过查看 `scripts` 属性来参考项目的一些操作 *** ### 三、cnpm #### 3.1 介绍 cnpm 是一个淘宝构建的 `npmjs.com` 的完整镜像,也称为『淘宝镜像』,网址 cnpm 服务部署在国内 `阿里云服务器上` , 可以提高包的下载速度 官方也提供了一个全局工具包 `cnpm` ,操作命令与 npm 大体相同 #### 3.2 安装 我们可以通过 npm 来安装 cnpm 工具 > npm install -g cnpm --registry= #### 3.3 操作命令 |功能|命令| |---|---| |初始化|cnpm init / cnpm init| |安装包|cnpm i uniq
cnpm i -S uniq
cnpm i -D uniq
cnpm i -g nodemon| |安装项目依赖|cnpm i| |删除|cnpm r uniq| #### 3.4 npm 配置淘宝镜像 用 npm 也可以使用淘宝镜像,配置的方式有两种 - 直接配置 - 工具配置 ##### 3.4.1 直接配置 执行如下命令即可完成配置 > npm config set registry ##### 3.4.2 工具配置 使用 `nrm` 配置 npm 的镜像地址 `npm registry manager` 1. 安装 nrm > npm i -g nrm 2. 修改镜像 > nrm use taobao 3. 检查是否配置成功(选做) > npm config list 检查 registry 地址是否为 , 如果 `是` 则表明成功 > 补充说明: > > 1. `建议使用第二种方式` 进行镜像配置,因为后续修改起来会比较方便 > 2. 虽然 cnpm 可以提高速度,但是 npm 也可以通过淘宝镜像进行加速,所以 `npm 的使用率还是高于 cnpm` *** ### 四、yarn
8
#### 4.1 yarn 介绍 yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方网址: #### 4.2 yarn 特点 yarn 官方宣称的一些特点 - 速度超快:yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大 化资源利用率,因此安装速度更快 - 超级安全:在执行代码之前,yarn 会通过算法校验每个安装包的完整性 - 超级可靠:使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的工作 #### 4.3 yarn 安装 我们可以使用 npm 安装 yarn #### 4.4 yarn 常用命令 > npm i -g yarn |功能|命令| |---|---| |初始化|yarn init / yarn init -y| |安装包|yarn add uniq 生产依赖
yarn add less --dev 开发依赖
yarn global add nodemon 全局安装| |删除包|yarn remove uniq 删除项目依赖包
yarn global remove nodemon 全局删除包| |安装项目依赖|yarn| |运行命令别名|yarn <别名> # 不需要添加 `run`| > 思考题: > > 这里有个小问题就是 `全局安装的包不可用` ,yarn 全局安装包的位置可以通过 `yarn global bin` 来查看,那你有没有办法使 yarn 全局安装的包能够正常运行? #### 4.5 yarn 配置淘宝镜像 可以通过如下命令配置淘宝镜像 > yarn config set registry 可以通过 `yarn config list` 查看 yarn 的配置项 #### 4.6 npm 和 yarn 选择 大家可以根据不同的场景进行选择 1. 个人项目 如果是个人项目, `哪个工具都可以` ,可以根据自己的喜好来选择 2. 公司项目 如果是公司要根据项目代码来选择,可以 `通过锁文件判断` 项目的包管理工具 - npm 的锁文件为 `package-lock.json` - yarn 的锁文件为 `yarn.lock` > 包管理工具 `不要混着用,切记,切记,切记` *** ### 五、管理发布包 #### 5.1 创建与发布 我们可以将自己开发的工具包发布到 npm 服务上,方便自己和其他开发者使用,操作步骤如下: 1. 创建文件夹,并创建文件 index.js, 在文件中声明函数,使用 module.exports 暴露 2. npm 初始化工具包,package.json 填写包的信息 (包的名字是唯一的) 3. 注册账号 4. 激活账号 ( `一定要激活账号` ) 5. 修改为官方的官方镜像 (命令行中运行 `nrm use npm` ) 6. 命令行下 `npm login` 填写相关用户信息 7. 命令行下 `npm publish` 提交包 👌 #### 5.2 更新包 后续可以对自己发布的包进行更新,操作步骤如下 1. 更新包中的代码 2. 测试代码是否可用 3. 修改 `package.json` 中的版本号 4. 发布更新 > npm publish #### 5.3 删除包 执行如下命令删除包 ```shell npm unpublish --force ``` > 删除包需要满足一定的条件, > > - 你是包的作者 > - 发布小于 24 小时 > - 大于 24 小时后,没有其他包依赖,并且每周小于 300 下载量,并且只有一个维护者 *** ### 六、扩展内容 在很多语言中都有包管理工具,比如: |语言|包管理工具| |---|---| |PHP|composer| |Python|pip| |Java|maven| |Go|go mod| |JavaScript|npm/yarn/cnpm/other| |Ruby|rubyGems| 除了编程语言领域有包管理工具之外,操作系统层面也存在包管理工具,不过这个包指的是『 `软件包` 』 |操作系统|包管理工具|网址| |---|---|---| |Centos|yum|| |Ubuntu|apt|| |MacOS|homebrew|| |Windows|chocolatey|| *** ## 07.NVM ***
1
*** ### 一、介绍 nvm 全称 `Node Version Manager` 顾名思义它是用来管理 node 版本的工具,方便切换不同版本的 Node.js ### 二、使用 nvm 的使用非常的简单,跟 npm 的使用方法类似 #### 2.1 下载安装 首先先下载 nvm,下载地址 ,选择 `nvm-setup.exe` 下载即可(网络异常的小朋友可以在资料文件夹中获取) #### 2.2 常用命令 |命令|说明| |---|---| |nvm|list available 显示所有可以下载的 Node.js 版本| |nvm|list 显示已安装的版本| |nvm|install 18.12.1 安装 18.12.1 版本的 Node.js| |nvm|install latest 安装最新版的 Node.js| |nvm|uninstall 18.12.1 删除某个版本的 Node.js| |nvm|use 18.12.1 切换 18.12.1 的 Node.js| *** ## 08.Express ***
1
*** ### 一、express 介绍 express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架,官方网址:< 简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务) *** ### 二、express 使用 #### 2.1 express 下载 express 本身是一个 npm 包,所以可以通过 npm 安装 ```shell npm init npm i express ``` #### 2.2 express 初体验 大家可以按照这个步骤进行操作: 1. 创建 JS 文件,键入如下代码 ```javascript //1. 导入 express const express = require('express'); //2. 创建应用对象 const app = express(); //3. 创建路由规则 app.get('/home', (req, res) => { res.end('hello express server'); }); //4. 监听端口 启动服务 app.listen(3000, () =>{ console.log('服务已经启动, 端口监听为 3000...'); }); ``` 2. 命令行下执行该脚本 ```shell node <文件名> # 或者 nodemon <文件名> ``` 3. 然后在浏览器就可以访问 👌 *** ### 三、express 路由 #### 3.1 什么是路由 官方定义: `路由确定了应用程序如何响应客户端对特定端点的请求` #### 3.2 路由的使用 一个路由的组成有 `请求方法` , `路径` 和 `回调函数` 组成 express 中提供了一系列方法,可以很方便的使用路由,使用格式如下: > app.\(path,callback) 代码示例: ```javascript //导入 express const express = require('express'); //创建应用对象 const app = express(); //创建 get 路由 app.get('/home', (req, res) => { res.send('网站首页'); }); //首页路由 app.get('/', (req,res) => { res.send('我才是真正的首页'); }); //创建 post 路由 app.post('/login', (req, res) => { res.send('登录成功'); }); //匹配所有的请求方法 app.all('/search', (req, res) => { res.send('1 秒钟为您找到相关结果约 100,000,000 个'); }); //自定义 404 路由 app.all("*", (req, res) => { res.send('

404 Not Found

') }); //监听端口 启动服务 app.listen(3000, () =>{ console.log('服务已经启动, 端口监听为 3000'); }); ``` #### 3.3 获取请求参数 express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式 ```javascript //导入 express const express = require('express'); //创建应用对象 const app = express(); //获取请求的路由规则 app.get('/request', (req, res) => { //1. 获取报文的方式与原生 HTTP 获取方式是兼容的 console.log(req.method); console.log(req.url); console.log(req.httpVersion); console.log(req.headers); //2. express 独有的获取报文的方式 //获取查询字符串 console.log(req.query); // 『相对重要』 // 获取指定的请求头 console.log(req.get('host')); res.send('请求报文的获取'); }); //启动服务 app.listen(3000, () => { console.log('启动成功....') }) ``` #### 3.4 获取路由参数 路由参数指的是 `URL 路径中的参数(数据)` ```javascript app.get('/:id.html', (req, res) => { res.send('商品详情, 商品 id 为' + req.params.id); }); ``` *** ### 四、express 响应设置 express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式 ```javascript //获取请求的路由规则 app.get("/response", (req, res) => { //1. express 中设置响应的方式兼容 HTTP 模块的方式 res.statusCode = 404; res.statusMessage = 'xxx'; res.setHeader('abc','xyz'); res.write('响应体'); res.end('xxx'); //2. express 的响应方法 res.status(500); //设置响应状态码 res.set('xxx','yyy');//设置响应头 res.send('中文响应不乱码');//设置响应体 //连贯操作 res.status(404).set('xxx','yyy').send('你好朋友') //3. 其他响应 res.redirect('http://atguigu.com')//重定向 res.download('./package.json');//下载响应 res.json();//响应 JSON res.sendFile(__dirname + '/home.html') //响应文件内容 }); let recordMiddleware = function(request,response,next){ //实现功能代码 //..... //执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next) next(); } ``` *** ### 五、express 中间件 #### 5.1 什么是中间件 `中间件(Middleware)本质是一个回调函数` `中间件函数` 可以像路由回调一样访问 `请求对象(request)` , `响应对象(response)` #### 5.2 中间件的作用 `中间件的作用` 就是 `使用函数封装公共操作,简化代码` #### 5.3 中间件的类型 - 全局中间件 - 路由中间件 ##### 5.3.1 定义全局中间件 `每一个请求` 到达服务端之后 `都会执行全局中间件函数` 声明中间件函数 ```javascript let recordMiddleware = function(request,response,next){ //实现功能代码 //..... //执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next) next(); } ```
2
应用中间件 ```javascript app.use(recordMiddleware); ``` 声明时可以直接将匿名函数传递给 `use` ```javascript app.use(function (request, response, next) { console.log('定义第一个中间件'); next(); }) ``` ##### 5.3.2 多个全局中间件 express 允许使用 app.use() 定义多个全局中间件 ```javascript app.use(function (request, response, next) { console.log('定义第一个中间件'); next(); }) app.use(function (request, response, next) { console.log('定义第二个中间件'); next(); }) ``` ##### 5.3.3 定义路由中间件 如果 只需要对某一些路由进行功能封装 ,则就需要路由中间件 调用格式如下: ```javascript app.get('/路径',`中间件函数`,(request,response)=>{ }); app.get('/路径',`中间件函数1`,`中间件函数2`,(request,response)=>{ }); ``` #### 5.4 静态资源中间件 express 内置处理静态资源的中间件 ```javascript //引入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)=>{ response.send('首页'); }); //监听端口 app.listen(3000,()=>{ console.log('3000 端口启动....'); }); ``` > 注意事项: > > 1. index.html 文件为默认打开的资源 > 2. 如果静态资源与路由规则同时匹配,谁先匹配谁就响应 > 3. 路由响应动态资源,静态资源中间件响应静态资源 #### 5.5 获取请求体数据 body-parser express 可以使用 `body-parser` 包处理请求体 第一步:安装 ```shell npm i body-parser ``` 第二步:导入 body-parser 包 ```javascript const bodyParser = require('body-parser'); ``` 第三步:获取中间件函数 ```javascript //处理 querystring 格式的请求体 let urlParser = bodyParser.urlencoded({extended:false})); //处理 JSON 格式的请求体 let jsonParser = bodyParser.json(); ``` 第四步:设置路由中间件,然后使用 `request.body` 来获取请求体数据 ```javascript app.post('/login', urlParser, (request,response)=>{ //获取请求体数据 //console.log(request.body); //用户名 console.log(request.body.username); //密码 console.log(request.body.userpass); response.send('获取请求体数据'); }); ``` 获取到的请求体数据: ```shell [Object: null prototype] { username: 'admin', userpass: '123456' } ``` *** ### 六、Router #### 6.1 什么是 Router express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。 #### 6.2 Router 作用 对路由进行模块化,更好的管理路由 #### 6.3 Router 使用 创建独立的 JS 文件(homeRouter.js) ```javascript //1. 导入 express const express = require('express'); //2. 创建路由器对象 const router = express.Router(); //3. 在 router 对象身上添加路由 router.get('/', (req, res) => { res.send('首页'); }) router.get('/cart', (req, res) => { res.send('购物车'); }); //4. 暴露 module.exports = router; ``` 主文件 ```javascript const express = require('express'); const app = express(); //5.引入子路由文件 const homeRouter = require('./routes/homeRouter'); //6.设置和使用中间件 app.use(homeRouter); app.listen(3000,()=>{ console.log('3000 端口启动....'); }) ``` *** ### 七、EJS 模板引擎 #### 7.1 什么是模板引擎 模板引擎是分离 `用户界面和业务数据` 的一种技术 #### 7.2 什么是 EJS EJS 是一个高效的 Javascript 的模板引擎 官网: 中文站: #### 7.3 EJS 初体验 下载安装EJS ```shell npm i ejs --save ``` 代码示例 ```javascript //1.引入ejs const ejs = require('ejs'); //2.定义数据 let person = ['张三','李四','王二麻子']; //3.ejs解析模板返回结构 //<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构 let html = ejs.render(‘<%= person.join(",") %>’, {person:person}); //4.输出结果 console.log(html); ``` 命令行下运行 #### 7.4 EJS 常用语法 执行JS代码 ```ejs <% code %> ``` 输出转义的数据到模板上 ```ejs <%= code %> ``` 输出非转义的数据到模板上 ```ejs <%- code %> ``` ***
1
## 09.MongoDB *** ### 一、简介 #### 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库,官方地址 #### 1.2 数据库是什么 数据库(DataBase)是按照数据结构来组织、存储和管理数据的 `应用程序` #### 1.3 数据库的作用 数据库的主要作用就是 `管理数据` ,对数据进行 `增(c)、删(d)、改(u)、查(r)` #### 1.4 数据库管理数据的特点 相比于纯文件管理数据,数据库管理数据有如下特点: 1. 速度更快 2. 扩展性更强 3. 安全性更强 #### 1.5 为什么选择 Mongodb 操作语法与 JavaScript 类似,容易上手,学习成本低 *** ### 二、核心概念 Mongodb 中有三个重要概念需要掌握 - 数据库(database) 数据库是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存放很多集合 - 集合(collection) 集合类似于 JS 中的数组,在集合中可以存放很多文档 - 文档(document) 文档是数据库中的最小单位,类似于 JS 中的对象
2
JSON 文件示例: ```json { "accounts": [ { "id": "3-YLju5f3", "title": "买电脑", "time": "2023-02-08", "type": "-1", "account": "5500", "remarks": "为了上网课" }, { "id": "3-YLju5f4", "title": "请女朋友吃饭", "time": "2023-02-08", "type": "-1", "account": "214", "remarks": "情人节聚餐" }, { "id": "mRQiD4s3K", "title": "发工资", "time": "2023-02-19", "type": "1", "account": "4396", "remarks": "终于发工资啦!~~" } ], "users": [ { "id": 1, "name": "zhangsan", "age": 18 }, { "id": 2, "name": "lisi", "age": 20 }, { "id": 3, "name": "wangwu", "age": 22 } ] } ``` 大家可以通过 JSON 文件来理解 Mongodb 中的概念 - 一个 `JSON 文件` 好比是一个 `数据库` ,一个 Mongodb 服务下可以有 N 个数据库 - JSON 文件中的 `一级属性的数组值` 好比是 `集合` - 数组中的对象好比是 `文档` - 对象中的属性有时也称之为 `字段` > 一般情况下 > 一个项目使用一个数据库 > 一个集合会存储同一种类型的数据 *** ### 三、下载安装与启动 下载地址: 建议选择 `zip` 类型, 通用性更强 配置步骤如下: 1> 将压缩包移动到 `C:\Program Files` 下,然后解压 2> 创建 `C:\data\db` 目录,mongodb 会将数据默认保存在这个文件夹 3> 以 mongodb 中 bin 目录作为工作目录,启动命令行 4> 运行命令 `mongod`
3
看到最后的 `waiting for connections` 则表明服务 `已经启动成功` 然后可以使用 `mongo` 命令连接本机的 mongodb 服务
4
> 注意: > > - 为了方便后续方便使用 mongod 命令,可以将 bin 目录配置到环境变量 Path 中 > - 千万不要选中服务端窗口的内容 ,选中会停止服务,可以 敲回车 取消选中 *** ### 四、命令行交互 **命令行交互一般是学习数据库的第一步,不过这些命令在后续用的比较少,所以大家了解即可.** #### 4.1 数据库命令 1. 显示所有的数据库 > show dbs 2. 切换到指定的数据库,如果数据库不存在会自动创建数据库 > use 数据库名 3. 显示当前所在的数据库 > db 4. 删除当前数据库 > use 库名 > db.dropDatabase() #### 4.2 集合命令 1. 创建集合 > db.createCollection('集合名称') 2. 显示当前数据库中的所有集合 > show collections 3. 删除某个集合 > db.集合名.drop() 4. 重命名集合 > db.集合名.renameCollection('newName') #### 4.3 文档命令 1. 插入文档 > db.集合名.insert(文档对象); 2. 查询文档 > db.集合名.find(查询条件) > `_id 是 mongodb 自动生成的唯一编号,用来唯一标识文档` 3. 更新文档 > db.集合名.update(查询条件,新的文档) > db.集合名.update({name:'张三'},{$set:{age:19}}) 4. 删除文档 > db.集合名.remove(查询条件) #### 4.4 应用场景 ##### 4.4.1 新增 - 用户注册 - 发布视频 - 发布商品 - 发朋友圈 - 发评论 - 发微博 - 发弹幕 - ....... ##### 4.4.2 删除 - 删除评论 - 删除商品 - 删除文章 - 删除视频 - 删除微博 - ...... ##### 4.4.3 更新 - 更新个人信息 - 修改商品价格 - 修改文章内容 - ...... ##### 4.4.4 查询 - 商品列表 - 视频列表 - 朋友圈列表 - 微博列表 - 搜索功能 - ..... *** ### 五、Mongoose #### 5.1 介绍 Mongoose 是一个对象文档模型库,官网 #### 5.2 作用 方便使用代码操作 mongodb 数据库 #### 5.3 使用流程 ```javascript //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: String, author: String, price: Number }); //6. 创建文档模型对象 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.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.5 字段值验证 Mongoose 有一些内建验证器,可以对字段值进行验证 ##### 5.5.1 必填项 ```json title: { type: String, required: true // 设置必填项 }, ``` ##### 5.5.2 默认值 ```json author: { type: String, default: '匿名' //默认值 }, ``` ##### 5.5.3 枚举值 ```json gender: { type: String, enum: ['男','女'] //设置的值必须是数组中的 }, ``` ##### 5.5.4 唯一值 ```json username: { type: String, unique: true }, ``` > unique 需要 `重建集合` 才能有效果 > 永远不要相信用户的输入 #### 5.6 CURD 数据库的基本操作包括四个,增加(create),删除(delete),修改(update),查(read) ##### 5.6.1 增加 插入一条 ```javascript SongModel.create({ title:'给我一首歌的时间', author: 'Jay' }, function(err, data){ //错误 console.log(err); //插入后的数据对象 console.log(data); }); ``` 批量插入 ```javascript //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 }) //6.创建模型对象 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(); }) }) ``` ##### 5.6.2 删除 删除一条数据 ```javascript SongModel.deleteOne({_id:'5dd65f32be6401035cb5b1ed'}, function(err){ if(err) throw err; console.log('删除成功'); mongoose.connection.close(); }); ``` 批量删除 ```javascript SongModel.deleteMany({author:'Jay'}, function(err){ if(err) throw err; console.log('删除成功'); mongoose.connection.close(); }); ``` ##### 5.6.3 更新 更新一条数据 ```javascript SongModel.updateOne({author: 'JJ Lin'}, {author: '林俊杰'}, function (err) { if(err) throw err; mongoose.connection.close(); }); ``` 批量更新数据 ```javascript SongModel.updateOne({author: 'JJ Lin'}, {author: '林俊杰'}, function (err) { if(err) throw err; mongoose.connection.close(); }); ``` ##### 5.6.4 查询 查询一条数据 ```javascript 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(); }); ``` 批量查询数据 ```javascript //不加条件查询 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.7 条件控制 ##### 5.7.1 运算符 在 mongodb 不能 > < >= <= !== 等运算符,需要使用替代符号 - `>` 使用 `$gt` - `<` 使用 `$lt` - `>=` 使用 `$gte` - `<=` 使用 `$lte` - `!==` 使用 `$ne` ```javascript db.students.find({id:{$gt:3}}); id号比3大的所有的记录 ``` ##### 5.7.2 逻辑运算 `$or` 逻辑或的情况 ```javascript db.students.find({$or:[{age:18},{age:24}]}); ``` `$and` 逻辑与的情况 ```javascript db.students.find({$and: [{age: {$lt:20}}, {age: {$gt: 15}}]}); ``` ##### 5.7.3 正则匹配 条件中可以直接使用 JS 的正则语法,通过正则可以进行模糊查询 ```javascript db.students.find({name:/imissyou/}); ``` #### 5.8 个性化读取 ##### 5.8.1 字段筛选 ```javascript //0:不要的字段 //1:要的字段 SongModel.find().select({_id:0,title:1}).exec(function(err,data){ if(err) throw err; console.log(data); mongoose.connection.close(); }); ``` ##### 5.8.2 数据排序 ```javascript //sort 排序 //1:升序 //-1:倒序 SongModel.find().sort({hot:1}).exec(function(err,data){ if(err) throw err; console.log(data); mongoose.connection.close(); }); ``` ##### 5.8.3 数据截取 ```javascript //skip 跳过 limit 限定 SongModel.find().skip(10).limit(10).exec(function(err,data){ if(err) throw err; console.log(data); mongoose.connection.close(); }); ``` *** ### 六、 图形化管理工具 我们可以使用图形化的管理工具来对 Mongodb 进行交互,这里演示两个图形化工具 - Robo 3T 免费 - Navicat 收费 *** ## 10.接口 *** ### 一、简介 #### 1.1 接口是什么 接口是 `前后端通信的桥梁` 简单理解:一个接口就是 `服务中的一个路由规则` ,根据请求响应结果 接口的英文单词是 API (Application Program Interface),所以有时也称之为 `API` 接口 这里的接口指的是『数据接口』, `与编程语言(Java,Go 等)中的接口语法不同` #### 1.2 接口的作用 实现 `前后端通信`
1
#### 1.3 接口的开发与调用 大多数接口都是由 `后端工程师` 开发的, `开发语言不限` 一般情况下接口都是由 `前端工程师` 调用的,但有时 `后端工程师也会调用接口` ,比如短信接口,支付接口等 #### 1.4 接口的组成 一个接口一般由如下几个部分组成 - 请求方法 - 接口地址(URL) - 请求参数 - 响应结果 一个接口示例
2
> 体验一下: *** ### 二、RESTful API RESTful API 是一种特殊风格的接口,主要特点有如下几个: - URL 中的路径表示 `资源` ,路径中不能有 动词 ,例如 `create` , `delete` , `update` 等这些都不能有 - 操作资源要与 `HTTP 请求方法` 对应 - 操作结果要与 `HTTP 响应状态码` 对应 规则示例: |操作|请求类型|URL|返回| |---|---|---|---| |新增歌曲|POST|/song|返回新生成的歌曲信息| |删除歌曲|DELETE|/song/10|返回一个空文档| |修改歌曲|PUT|/song/10|返回更新后的歌曲信息| |修改歌曲|PATCH|/song/10|返回更新后的歌曲信息| |获取所有歌曲|GET|/song|返回歌曲列表数组| |获取单个歌曲|GET|/song/10|返回单个歌曲信息| > 扩展阅读: *** ### 三、json-server json-server 本身是一个 JS 编写的工具包,可以快速搭建 RESTful API 服务 官方地址: 操作步骤: 1. 全局安装 `json-server` > npm i -g json-server 2. 创建 JSON 文件(db.json),编写基本结构 ```json { "song": [ { "id": 1, "name": "干杯", "singer": "五月天" }, { "id": 2, "name": "当", "singer": "动力火车" }, { "id": 3, "name": "不能说的秘密", "singer": "周杰伦" } ] } ``` 3. `以 JSON 文件所在文件夹作为工作目录` ,执行如下命令 > json-server --watch db.json 默认监听端口为 3000 *** ### 四、接口测试工具 介绍几个接口测试工具 - apipost (中文) - apifox (中文) - postman (英文) *** ## 11.会话控制 *** ### 一、介绍 所谓会话控制就是 `对会话进行控制` HTTP 是一种无状态的协议,它没有办法区分多次的请求是否来自于同一个客户端, `无法区分用户` 而产品中又大量存在的这样的需求,所以我们需要通过 `会话控制` 来解决该问题 常见的会话控制技术有三种: - cookie - session - token *** ### 二、cookie #### 2.1 cookie 是什么 cookie 是 HTTP 服务器发送到用户浏览器并保存在本地的一小块数据 `cookie 是保存在浏览器端的一小块数据` `cookie 是按照域名划分保存的` 简单示例: |域名|cookie| |---|---| |www.baidu.com|a=100; b=200| |www.bilibili.com|xid=1020abce121; hm=112411213| |jd.com|x=100; ocw=12414cce| #### 2.2 cookie 的特点 浏览器向服务器发送请求时,会自动将 `当前域名下` 可用的 cookie 设置在请求头中,然后传递给服务器
1
这个请求头的名字也叫 `cookie` ,所以将 `cookie 理解为一个 HTTP 的请求头也是可以的` #### 2.3 cookie 的运行流程 填写账号和密码校验身份,校验通过后下发 cookie
2
有了 cookie 之后,后续向服务器发送请求时,就会自动携带 cookie
3
#### 2.4 浏览器操作 cookie 浏览器操作 cookie 的操作,使用相对较少,大家了解即可 1. 禁用所有 cookie 2. 删除 cookie 3. 查看 cookie #### 2.5 cookie 的代码操作 express 中可以使用 `cookie-parser` 进行处理 ```javascript const express =require('express'); //1. 安装 cookie-parser npm i cookie-parser //2. 引入 cookieParser 包 const cookieParser = require('cookie-parser'); const app = express(); //3. 设置 cookieParser 中间件 app.use(cookieParser()); //4-1 设置 cookie app.get('/set-cookie', (request, response) => { // 不带时效性 response.cookie('username','wangwu'); // 带时效性 response.cookie('email','23123456@qq.com', {maxAge: 5*60*1000 }); //响应 response.send('Cookie的设置'); }); //4-2 读取 cookie app.get('/get-cookie', (request, response) => { //读取 cookie console.log(request.cookies); //响应体 response.send('Cookie的读取'); }); //4-3 删除cookie app.get('/delete-cookie', (request, response) => { //删除 response.clearCookie('username'); //响应 response.send('cookie 的清除'); }); //4. 启动服务 app.listen(3000, () => { console.log('服务已经启动....'); }); ``` > 不同浏览器中的 cookie 是相互独立的,不共享 *** ### 三、session #### 3.1 session 是什么 session 是保存在 `服务器端的一块儿数据` ,保存当前访问用户的相关信息 #### 3.2 session 的作用 实现会话控制,可以识别用户的身份,快速获取当前用户的相关信息 #### 3.3 session 运行流程 填写账号和密码校验身份,校验通过后创建 `session 信息` ,然后将 `session_id` 的值通过响应头返回给浏览器
4
有了 cookie,下次发送请求时会自动携带 cookie,服务器通过 `cookie` 中的 `session_id` 的值确定用户的身份
5
#### 3.4 session 的代码操作 express 中可以使用 `express-session` 对 session 进行操作 ```javascript const express = require('express'); //1. 安装包 npm i express-session connect-mongo //2. 引入 express-session connect-mongo const session = require("express-session"); const MongoStore = require('connect-mongo'); const app = express(); //3. 设置 session 的中间件 app.use(session({ name: 'sid', //设置cookie的name,默认值是:connect.sid secret: 'atguigu', //参与加密的字符串(又称签名) saveUninitialized: false, //是否为每次请求都设置一个cookie用来存储session的id resave: true, //是否在每次请求时重新保存session store: MongoStore.create({ mongoUrl: 'mongodb://127.0.0.1:27017/project' //数据库的连接配置 }), cookie: { httpOnly: true, // 开启后前端无法通过 JS 操作 maxAge: 1000 * 300 // 这一条 是控制 sessionID 的过期时间的!!! }, })) //创建 session app.get('/login', (req, res) => { //设置session req.session.username = 'zhangsan'; req.session.email = 'zhangsan@qq.com' res.send('登录成功'); }) //获取 session app.get('/home', (req, res) => { console.log('session的信息'); console.log(req.session.username); if (req.session.username) { res.send(`你好 ${req.session.username}`); }else{ res.send('登录 注册'); } }) //销毁 session app.get('/logout', (req, res) => { //销毁session // res.send('设置session'); req.session.destroy(() => { res.send('成功退出'); }); }); app.listen(3000, () => { console.log('服务已经启动, 端口 ' + 3000 + ' 监听中...'); }); ``` *** ### 四、session 和 cookie 的区别 cookie 和 session 的区别主要有如下几点: 1. 存在的位置 - cookie:浏览器端 - session:服务端 2. 安全性 - cookie 是以明文的方式存放在客户端的,安全性相对较低 - session 存放于服务器中,所以安全性 `相对` 较好 3. 网络传输量 - cookie 设置内容过多会增大报文体积, 会影响传输效率 - session 数据存储在服务器,只是通过 cookie 传递 id,所以不影响传输效率 4. 存储限制 - 浏览器限制单个 cookie 保存的数据不能超过 `4K` ,且单个域名下的存储数量也有限制 - session 数据存储在服务器中,所以没有这些限制 *** ### 五、token #### 5.1 token 是什么 `token` 是服务端生成并返回给 HTTP 客户端的一串加密字符串, `token` 中保存着 `用户信息` #### 5.2 token 的作用 实现会话控制,可以识别用户的身份,主要用于移动端 APP #### 5.3 token 的工作流程 填写账号和密码校验身份,校验通过后响应 token,token 一般是在响应体中返回给客户端的
6
后续发送请求时,需要手动将 token 添加在请求报文中,一般是放在请求头中
7
#### 5.4 token 的特点 - 服务端压力更小 - 数据存储在客户端 - 相对更安全 - 数据加密 - 可以避免 CSRF(跨站请求伪造) - 扩展性更强 - 服务间可以共享 - 增加服务节点更简单 #### 5.5 JWT JWT(JSON Web Token )是目前最流行的跨域认证解决方案,可用于基于 `token` 的身份验证 JWT 使 token 的生成与校验更规范 我们可以使用 `jsonwebtoken 包` 来操作 token ```javascript //导入 jsonwebtokan const jwt = require('jsonwebtoken'); //创建 token // jwt.sign(数据, 加密字符串, 配置对象) let token = jwt.sign({ username: 'zhangsan' }, 'atguigu', { expiresIn: 60 //单位是 秒 }) //解析 token jwt.verify(token, 'atguigu', (err, data) => { if(err){ console.log('校验失败~~'); return } console.log(data); }) ``` > 扩展阅读: *** ### 六、附录 #### 6.1 本地域名 所谓本地域名就是 `只能在本机使用的域名` ,一般在开发阶段使用 #### 6.1.1 操作流程 编辑文件 `C:\Windows\System32\drivers\etc\hosts` ```ini 127.0.0.1 www.baidu.com ``` 如果修改失败, `可以修改该文件的权限`
8
#### 6.1.2 原理 在地址栏输入 `域名` 之后,浏览器会先进行 DNS(Domain Name System) 查询,获取该域名对应的 IP 地址 请求会发送到 DNS 服务器,可以 `根据域名返回 IP 地址` 可以通过 `ipconfig /all` 查看本机的 DNS 服务器 `hosts` 文件也可以设置域名与 IP 的映射关系,在发送请求前,可以通过该文件获取域名的 IP 地址 ***