Nodejs
为什么学习Node.js?
加入你有一个网页,你有没有办法让别人都访问这个网页?
这个就是Node.js的作用了,至于它是如何让每一个人都访问到的,后面会详细展开
前端开发三大框架
Vue React Angular
.assets/image-20250609200213029.png)
这三个项目开发的时候都离不开Node.js,是一个必学项。
所以总结来说:
1.可以让其他人访问我们编写的网页
2.为后续的框架学习打基础
Node.js是什么?
有人说:Node.js 是一门编程语言,也有人说Node.js是新版本的JavaScript? 那我们来看看官方是如何描述Node.js的:Node.js® 是一个免费、开源、跨平台的 JavaScript 运行时环境, 它让开发人员能够创建服务器 Web 应用、命令行工具和脚本。
通俗来讲:Node.js 就是一款应用程序,是一款软件,它可以运行JavaScript
Node.js 的作用
1.开发服务器应用
2.开发工具类应用
3.开发桌面端应用
我们下面来展开说一下:
1.开发服务器应用
.assets/image-20250609200702080.png)
Node.js 就可以是在B站服务器里面的软件。
我们前面说我们学习Node.js可以让别人访问到我们的网页,我们知道网页是由HTML,CSS,JavaScript 三件套组成的。那如果我们想让别人访问我们就必须使用服务器,但是服务器只有硬件,那么还得需要软件,Node.js就可以运行在服务器端,这样就可以让别人来访问我们的网站了。
2.开发工具类应用
.assets/image-20250609201015180.png)
3.开发桌面端应用
.assets/image-20250609201050195.png)
这三个应用都是使用electron,而electron是基于node.js开发出来的。以后可以去学习electron就可以进行开发了
Node.js 下载和安装
官网:Node.js — 在任何地方运行 JavaScript
怎么验证安装成功了吗?
使用cmd:然后输入node -v
认识命令行工具
你有没有办法不使用鼠标来打开QQ?
我们可以使用键盘上下左右,然后按回车
还没有办法呢?
我们可以使用一些快速启动工具,比如uTools
我们还可以使用cmd (win+R)
命令的结构
思考题:
如何使用命令行工具打开谷歌浏览器并访问百度首页?
win+R 输入cmd,在控制台中输入chrome http://www.baidu.com 然后输入回车即可
chrome 是命令 ,网址后面是参数 如果后面再加http://bilibli.com 就会打开两个网页
常用命令
命令行如何查看【D:/Program Files 】里的内容?
我们可以cd(change directory) 到 cd /d D:/Program Files 然后输出dir
切换盘符直接 D: 即可
Node.js 初体验
dir /s 是查看文件夹下所有的文件,ctrl+C可以停止
如果我们在hello.js中写下这样的代码:
1 | console.log('hello Node.js'); |
我们在控制台中操作:
1 | D:\Note\code\nodejs>node hello.js |
Node.js注意点
Node.js中不能使用BOM和DOM的API
.assets/image-20250609202927856.png)
.assets/image-20250609202936856.png)
1.Node.js中不能使用BOM和DOM的API,可以使用console和定时器API
2.Node.js中的顶级对象为global,也可以使用globalThis 访问顶级对象
Buffer
Buffer 中文译为【缓冲区】,是一个类似于Array的对象,用于表示固定长度的字节序列
换句话说,Buffer就是一段固定长度的内存空间,用于处理二进制数据
.assets/image-20250609203343347.png)
特点
1.Buffer 大小固定且无法调整
2.Buffer 性能较好,可以直接对计算机内存进行操作
3.每个元素的大小为 1 字节(byte)
.assets/image-20250609203455768.png)
使用
创建 Buffer Node.js 中创建 Buffer 的方式主要如下几种:
1.Buffer.alloc
1 | //1.alloc |
1 | PS D:\Note\code\nodejs> node .\创建buffer.js |
2.Buffer.allocUnsafe
1 | //2.allocUnsafe |
3.Buffer.from
1 | //3.from 通过字符串创建buffer |
**Buffer与字符串的转化 **
我们可以借助 toString 方法将 Buffer 转为字符串
1 | let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]); |
1 | PS D:\Note\code\nodejs> node .\操作buffer.js |
【这也可以是一种表白的方式】
toString 默认是按照 utf-8 编码方式进行转换的。
**Buffer 的读写 **
Buffer 可以直接通过 [] 的方式对数据进行处理。
1 | //读取 |
注意:
如果修改的数值超过 255 ,则超过 8 位数据会被舍弃
一个 utf-8 的字符 一般 占 3 个字节
计算机基本组成
CPU 内存 硬盘
内存:读写速度较快,断电丢失数据
硬盘:读写速度较慢,断电不丢失数据
主板:集成电路板
显卡:负责处理视频信号,当有信息需要呈现时,需要在屏幕中呈现就会将信息传递给显卡,显卡处理好后再传递给显示器。
机箱
外设
程序运行的基本流程
操作系统
windows, linux MacOS
操作系统也是一种应用程序,用来管理和调度硬件资源
.assets/image-20250609205140863.png)
英雄联盟是如何运行的?
.assets/image-20250609205248548.png)
小结:
程序一般保存再在硬盘中,软件安装的过程就是将程序写入硬盘的过程。
程序在运行时会加载进入内存,然后由CPU读取并执行程序
进程和线程
进程:运行的程序
进程是程序的一次执行过程
可以通过任务管理器进行查看
线程:
线程是一个进程中执行的一个执行流
一个线程是属于某个进程的
可以通过pslist -dmx [PID]
线程和进程的关系
比如说有一家蜜雪冰城的奶茶店
当开店的时候就好比是进程开始运行,有很多的员工,这里的员工就是线程
fs模块
fs : file System
这个跟硬盘相关,fs模块可以实现与硬盘的交互。例如文件的创建,删除,重命名,移动,还有文件内容的写入,读取,以及文件夹的相关操作
fs 全称为 file system ,称之为 文件系统 ,是 Node.js 中的 内置模块 ,可以对计算机中的磁盘进行操 作。
本章节会介绍如下几个操作:
文件写入
文件读取
文件移动与重命名
文件删除
文件夹操作
查看资源状态
一、文件写入
文件写入就是将 数据 保存到 文件 中,我们可以使用如下几个方法来实现该效果
| 方法 | 说明 |
|---|---|
| writeFile | 异步写入 |
| writeFileSync | 同步写入 |
| appendFile / appendFileSync | 追加写入 |
| createWriteStream | 流式写入 |
1 - 1. writeFile异步写入
语法: fs.writeFile(file, data[, options], callback)
参数说明:
file:文件名data:待写入的数据options(可选):选项设置callback:写入回调
返回值: undefined
1 | /** |
明明右键就可以新建,为什么我们要用代码?
举个例子:
比如我们有一个网站,我们希望记录用户每次访问我们网站的时间,并且记录在一个文件中。难道安排一个人吗?
vscode 也是借助了fs这个模块
fs异步与同步
小明和小红去打篮球,小红突然说要去测试,那这个时候如果我等他一起去那就是同步,但是如果我先去它后来那就是异步。
1 - 2. writeFileSync 同步写入
语法:fs.writeFileSync(file, data[, options])
参数说明:参数与 fs.writeFile 大体一致,只是没有 callback 参数。
返回值:undefined
代码示例:
1 | const fs = require('fs'); |
Node.js 磁盘操作模式说明:
Node.js 中的磁盘操作是由其他线程完成的,结果的处理有两种模式:
- 同步处理:JavaScript 主线程会等待其他线程的执行结果,然后再继续执行主线程的代码,效率较低。
- 异步处理:JavaScript 主线程不会等待其他线程的执行结果,直接执行后续的主线程代码,效率较好。
1 - 3. appendFile / appendFileSync 追加写入
appendFile 的作用是在文件尾部追加内容,它的语法和 writeFile 完全相同。
语法:
fs.appendFile(file, data[, options], callback)fs.appendFileSync(file, data[, options])
返回值:二者都为 undefined
实例代码:
1 | const fs = require('fs'); |
1 - 4. createWriteStream 流式写入
语法:fs.createWriteStream(path[, options])
参数说明:
path:文件路径options(可选):选项配置
返回值:Object
代码示例:
1 | let ws = fs.createWriteStream('./观书有感.txt'); |
特点说明:
- 资源消耗:程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数。
- 适用场景:流式写入方式适用于大文件写入或者频繁写入的场景,
writeFile适合于写入频率较低的场景。
1 - 5. 写入文件的场景
文件写入在计算机中是一个非常常见的操作,下面的场景都用到了文件写入:
- 下载文件
- 安装软件
- 保存程序日志,如 Git
- 编辑器保存文件
- 视频录制
当需要持久化保存数据的时候,应该想到文件写入 。
二、文件读取
文件读取顾名思义,就是通过程序从文件中取出其中的数据,我们可以使用如下几种方式:
| 方法 | 说明 |
|---|---|
| readFile | 异步读 |
| readFileSync | 同步读 |
| createReadStream | 流式读 |
2 - 1. readFile 异步读取
语法:fs.readFile(path[, options], callback)
参数说明:
path:文件路径options:选项配置(可选)callback:回调函数,第一个参数为错误对象err(若读取无错误则为null),第二个参数为读取到的数据data
返回值:undefined
代码示例:
1 | // 导入 fs 模块 |
说明:
- 第一种
readFile调用方式,如果不指定编码('utf -8'),data是Buffer(缓冲区)类型,它是一个类似数组的对象,用于表示二进制数据。 - 第二种
readFile调用方式,指定了编码'utf -8',data会被自动转换为字符串类型,方便直接处理文本内容。
2 - 2. readFileSync 同步读取
语法:fs.readFileSync(path[, options])
参数说明:
path:文件路径options:选项配置(可选)
返回值:读取到的数据(是 Buffer 类型或者根据指定编码转换后的字符串类型)
代码示例:
1 | const fs = require('fs'); |
说明:
readFileSync是同步读取文件,即 JavaScript 主线程会等待文件读取完成后才继续执行后续代码。- 它的返回值直接是读取到的数据,不像
readFile通过回调函数获取数据。
2 - 3. createReadStream 流式读取
语法:fs.createReadStream(path[, options])
参数说明:
path:文件路径options:选项配置(可选)
返回值:ReadStream 对象
代码示例:
1 | const fs = require('fs'); |
说明:
- 流式读取适合读取大文件,它不会一次性将整个文件读入内存,而是分块读取(
chunk表示读取到的数据块)。 - 通过监听
ReadStream对象的'data'、'end'、'error'等事件来处理读取过程中的不同情况。
2 - 4读取文件应用场景
- 电脑开机
- 程序运行
- 编辑器打开文件
- 查看图片
- 播放视频
- 播放音乐
- Git查看日志
- 上传文件
- 查看聊天记录
复制文件
1 | /** |
三、文件移动与重命名
在 Node.js 中,我们可以使用 rename 或 renameSync 来移动或重命名 文件或文件夹。
语法:
fs.rename(oldPath, newPath, callback)fs.renameSync(oldPath, newPath)
参数说明:
oldPath:文件当前的路径newPath:文件新的路径callback:操作后的回调
代码示例:
1 | fs.rename('../观书有感.txt', '../论语/观书有感.txt', (err) =>{ |
四、文件删除
在 Node.js 中,我们可以使用 unlink 或 unlinkSync 来删除文件
语法:
fs.unlink(path, callback)fs.unlinkSync(path)- 也可以使用rm rmSync
参数说明:
path:文件路径callback:操作后的回调
代码示例:
1 | // 异步删除文件示例 |
五、文件夹操作
借助 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:操作后的回调
示例代码:
1 | // 异步创建文件夹 |
5 - 2 readdir 读取文件夹
在 Node.js 中,我们可以使用 readdir 或 readdirSync 来读取文件夹
语法:
fs.readdir(path[, options], callback)fs.readdirSync(path[, options])
参数说明:
path:文件夹路径options:选项配置(可选)callback:操作后的回调
示例代码:
1 | // 异步读取 |
5 - 3 rndir 删除文件夹
在 Node.js 中,我们可以使用 rndir 或 rndirSync 来删除文件夹
语法:
fs.rmdir(path[, options], callback)fs.rmdirSync(path[, options])
参数说明:
path:文件夹路径options:选项配置(可选)callback:操作后的回调
示例代码:
1 | //异步删除文件夹 |
注意:
rmdir和rmdirSync只能删除空文件夹,如果要删除非空文件夹,需要先删除文件夹内的所有文件和子文件夹。- 在实际应用中,为了确保安全,建议在删除文件夹之前先确认其内容是否为预期,避免误删重要数据。
六、查看资源状态
在 Node.js 中,我们可以使用 stat 或 statSync 来查看资源的详细信息
语法:
fs.stat(path[, options], callback)fs.statSync(path[, options])
参数说明:
path:文件夹路径options:选项配置(可选)callback:操作后的回调
示例代码:
1 | // 异步获取状态 |
说明:
stat 方法返回的 data 对象包含了文件或文件夹的各种信息,例如:
data.isFile():判断是否为文件data.isDirectory():判断是否为目录(文件夹)data.size:文件大小(字节数)data.birthtime:创建时间data.mtime:最后修改时间等。
通过这些信息可以更深入地了解文件或文件夹的属性和状态,以便进行相应的处理操作。
结果值对象结构:
- 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与文件名拼接成绝对路径。
代码示例:
1 | let data = fs.readFileSync(__dirname + '/data.txt'); |
- 使用
fs模块的时候,尽量使用__dirname将路径转化为绝对路径,这样可以避免相对路径产生的 Bug
练习:批量重命名
1 | //导入fs |
如果把02删除了 能不能把03变02,04变03?
1 | const fs = require('fs'); |
path 模块
path 模块提供了 操作路径 的功能,我们将介绍如下几个较为常用的几个 API:
| API | 说明 |
|---|---|
| path.resolve | 拼接规范的绝对路径 常用 |
| path.sep | 获取操作系统的路径分隔符 |
| path.parse | 解析路径并返回对象 |
| path.basename | 获取路径的基础名称 |
| path.dirname | 获取路径的目录名 |
| path.extname | 获得路径的扩展名 |
代码示例:
1 | const path = require('path'); |
HTTPS协议
一、概念
HTTP(hypertext transport protocoI)协议;中文叫超文本传输协议。 是一种基于 TCP/IP 的应用层通信协议。 这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。 协议中主要规定了两个方面的内容:
- 客户端:用来向服务器发送数据,可以被称之为请求报文。
- 服务端:向客户端返回数据,可以被称之为响应报文。
报文:可以简单理解为就是一堆字符串。
【离婚协议,保密协议 https协议就是浏览器和服务器之间的协议】
如果我们想看到请求和响应的报文我们要下载一个软件叫fiddler
.assets/image-20250609221641878.png)
二、请求报文的组成
- 请求行
- 请求头
- 空行
- 请求体
三、HTTP 的请求行
-
请求方法(get、post、put、delete等)
-
请求 URL(统一资源定位器)
-
例如:
http://www.baidu.com:80/index.html?a=100&b=200#logo
- http: 协议(https、ftp、ssh等)
- www.baidu.com 域名
- 80 端口号
- /index.html 路径
- a=100&b=200 查询字符串
- #logo 哈希(锚点链接)
-
-
HTTP 协议版本号
查询字符串和路径有什么区别?比如我要去买煎饼果子,这个就是路径,我说我煎饼果子要加辣椒要加根肠那就查询字符串
.assets/image-20250609222915592.png)
四、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}
六、响应报文的组成
- 响应行
1 | HTTP/1.1 200 OK |
- HTTP/1.1:HTTP 协议版本号
- 200:响应状态码 404 Not Found 500 Internal Server Error 还有一些状态码,参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
- OK:响应状态描述
响应状态码和响应字符串关系是一一对应的。
- 响应头
| 响应头 | 解释 |
|---|---|
| Cache - Control | 缓存控制 (private 私有,只允许客户端缓存数据) |
| Connection | 链接设置 |
| Content - Type | 设置响应体的数据类型以及字符集(如:text/html;charset=utf - 8 ,表示响应体为 html,字符集 utf - 8) |
| Content - Length | 响应体的长度,单位为字节 |
- 空行
- 响应体 响应体内容的类型是非常灵活的,常见的类型有 HTML、CSS、JS、图片、JSON
七、创建 HTTP 服务
地址 ==》 寻找收件人
IP ==》 寻找网络设备
IP也称为【IP地址】,本身是一个数字标识 例如 192.168.1.3
IP 用来标识网络中的设备,实现设备间通信
.assets/image-20250610001641463.png)
IP的分类
32Bit IPV4 已经不够
如何解决?
共享IP
区域共享 家庭共享
局域网IP(又称之为私网IP)在这个网络里面我们的设备是可以相互通信的,比如手机可以给电脑发一个文件,电脑可以发一个视频给手机,这些都是可以的。但是如果你想跟小伙伴开黑,打视频那这个是做不到的。必须连接互联网,去通信公司办理业务,国内主要有三家电信,联通,移动。师傅会上门帮你的路由器接一根线,然后你的路由器就会得到广域网IP或公网IP,我们说所的共享IP其实是公网IP
本地回环IP地址
127.0.0.1 其实就是本机
127.0.0.1~127.255.255.254
.assets/image-20250610083606917.png)
IP标准分类 : https://zhuanlan.zhihu.com/p/193729352
端口
端口举例
.assets/image-20250610083823911.png)
应用程序的数字标识
一台现代计算机有65536 个端口(0~65535)
一个应用程序可以使用一个或多个端口
端口的主要作用:实现不同主机应用程序之间的通信
身份转换~ 到后端啦
使用 nodejs 创建 HTTP 服务
7.1 操作步骤
1 | // 1. 导入 http 模块 |
7.2测试
浏览器请求对应端口
http://127.0.0.1:9000
7.3注意事项
1.命令行ctr1+c停止服务
2.当服务启动后,更新代码必须重启服务才能生效
3.响应内容中文乱码的解决办法
1 | response.setHeader('content-type','text/html;charset=utf-8'); |
4.端口号被占用
1 | Error:listen EADDRINUSE:address already in use 9000 |
1)关闭当前正在运行监听端口的服务(使用较多)
2)修改其他端口号
HTTP协议默认端口
- HTTP协议默认端口是80。
- HTTPS协议的默认端口是443。
- HTTP服务开发常用端口有3000、8080、8090、9000等。
端口被占用处理
如果端口被其他程序占用,可以使用资源监视器找到占用端口的程序,然后使用任务管理器关闭对应的程序。
八、浏览器查看HTTP报文
f12
九、获取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(){}); |
注意事项:
- request.url 只能获取路径以及查询字符串,无法获取 URL 中的域名以及协议的内容
- request.headers 将请求信息转化成一个对象,并将属性名都转化成了『小写』
- 关于路径:如果访问网站的时候,只填写了 IP 地址或者是域名信息,此时请求的路径为『 / 』
- 关于 favicon.ico:这个请求是属于浏览器自动发送的请求
9.1 练习
按照以下要求搭建 HTTP 服务
| 请求类型(方法) | 请求地址 | 响应体结果 |
|---|---|---|
| get | /login | 登录页面 |
| get | /reg | 注册页面 |
1 | //1、引入http模块 |
十、设置 HTTP 响应报文
| 作用 | 语法 |
|---|---|
| 设置响应状态码 | response.statusCode |
| 设置响应状态描述 | response.statusMessage(用的非常少) |
| 设置响应头信息 | response.setHeader('头名', '头值') |
| 设置响应体 | response.write('xx')``response.end('xxx') |
write 和 end 的两种使用情况:
1. write 和 end 的结合使用(响应体相对分散)
1 | response.write('xx'); |
2. 单独使用 end 方法(响应体相对集中)
1 | response.end('xxx'); |
10.1 练习
搭建 HTTP 服务,响应一个 4 行 3 列的表格,并且要求表格有隔行换色效果,且点击单元格能高亮显示
1 | //导入 http 模块 |
核心代码解释:
- 在 HTML 表格标签
<table>中,通过nth - child(odd)和nth - child(even)实现了表格的隔行换色效果。 - 在
<script>标签中,通过document.querySelectorAll('td')获取到了所有的<td>标签元素,并通过遍历遍历为每个td元素添加了onclick事件。 - 在
onclick事件中,通过this.style.background = '#222'实现了点击单元格时的高亮显示效果。
HTTP 服务搭建核心逻辑:
- 首先导入
http模块。 - 然后通过
http.createServer创建了一个 HTTP 服务,在这个服务的回调函数中,返回了包含上述 HTML 代码的响应体。 - 最后通过
server.listen监听了8080端口,并在服务启动时打印了提示信息。
优化:
有没有办法解决在这里面写html代码有高亮和提示?
table.html
1 |
|
node.js
1 | //导入 http 模块 |
十一、网页资源的基本加载过程
网页资源的加载都是循序渐进的,首先获取 HTML 的内容, 然后解析 HTML 在发送其他资源的请求,如 CSS,Javascript,图片等。 理解了这个内容对于后续的学习与成长有非常大的帮助
如果要对上面哪个练习进行进一步的拆分:
1 | //导入 http 模块 |
十二、静态资源服务
静态资源是指 内容长时间不发生改变的资源 ,例如图片,视频,CSS 文件,JS文件,HTML文件,字体文 件等
动态资源是指 内容经常更新的资源 ,例如百度首页,网易首页,京东搜索列表页面等
**12.1网站根目录或静态资源目录 **
HTTP 服务在哪个文件夹中寻找静态资源,那个文件夹就是 静态资源目录 ,也称之为 网站根目录
思考:vscode 中使用 live-server 访问 HTML 时, 它启动的服务中网站根目录是谁?
以打开文件夹
12.2 网页中的 URL
网页中的 URL 主要分为两大类:相对路径与绝对路径
12.2.1 绝对路径
绝对路径可靠性强,而且相对容易理解,在项目中运用较多
| 形式 | 特点 |
|---|---|
http://yjy.com/web |
直接向目标资源发送请求,容易理解。网站的外链会用到此形式 |
//yjy.com/web |
与页面 URL 的协议拼接形成完整 URL 再发送请求。大型网站用的比较多 |
/web |
与页面 URL 的协议、主机名、端口拼接形成完整 URL 再发送请求。中小型网站 |
12.2.2 相对路径
相对路径在发送请求时,需要与当前页面 URL 路径进行 计算,得到完整 URL 后,再发送请求,学习阶段用的较多
例如当前网页 url 为 http://www.yjy.com/course/h5.html
| 形式 | 最终的 URL |
|---|---|
.css/app.css |
http://www.yjy.com/course/css/app.css |
js/app.js |
http://www.yjy.com/course/js/app.js |
../img/logo.png |
http://www.yjy.com/img/logo.png |
../../mp4/show.mp4 |
http://www.yjy.com/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 类型)是一种标准,用来表示文档、文件或字节流的性质和格式。
mime 类型结构: [type]/[subType]
例如: text/html text/css image/jpeg image/png application/json
HTTP 服务可以设置响应头 Content-Type 来表明响应体的 MIME 类型,浏览器会根据该类型决定如何处理资源
下面是常见文件对应的 mime 类型
1 | html: 'text/html', |
1 | /** |
对于未知的资源类型,可以选择 application/octet-stream 类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的 下载 效果
1 | require('http').createServer((request, response) => { |
改进 HTTP 服务器代码(文件路径封装)
原始问题:之前的代码每增加一个请求路径就需要进行单独判断,不够灵活和完善。
改进思路:将文件路径相关逻辑进行封装,实现通用的文件请求处理。
改进代码:
1 | const http = require('http'); |
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 请求则没有大小限制
Node.js 模块化
一、介绍
- 什么是模块化与模块? 将一个复杂的程序文件依据一定规则 (规范) 拆分成多个文件的过程称之为 模块化
其中拆分出的 每个文件就是一个模块,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用
- 什么是模块化项目? 编码时是按照模块一个一个编码的,整个项目就是一个模块化的项目
- 模块化好处 下面是模块化的一些好处:
- 防止命名冲突
- 高复用性
- 高维护性
二、模块暴露数据
2.1 模块初体验
可以通过下面的操作步骤,快速体验模块化:
- 创建
me.js
1 | //声明函数 |
- 创建
index.js
1 | //导入模块 |
2.2 暴露数据
模块暴露数据的方式有两种:
module.exports = valueexports.name = value
使用时有几点注意:
module.exports可以暴露 任意 数据- 不能使用
exports = value的形式暴露数据,模块内部module与exports的隐式关系exports = module.exports = {},require返回的是目标模块中module.exports的值
.assets/image-20250610110144642.png)
三、导入(引入)模块
在模块中使用 require 传入文件路径即可引入文件
1 | const test = require('./me.js'); |
require 使用的一些注意事项:
- 对于自己创建的模块,导入时路径建议写
相对路径,且不能省略./和../ js和json文件导入时可以不用写后缀,c/c++编写的node扩展文件也可以不写后缀,但是一般用不到- 如果导入其他类型的文件,会以
js文件进行处理 - 如果导入的路径是个文件夹,则会 首先 检测该文件夹下
package.json文件中main属性对应的文件,
如果存在则导入,反之如果文件不存在会报错。
如果 main 属性不存在,或者 package.json 不存在,则会尝试导入文件夹下的 index.js 和 index.json,
如果还是没找到,就会报错 5. 导入 node.js 内置模块时,直接 require 模块的名字即可,无需加 ./ 和 ../
四、导入模块的基本流程
这里我们介绍一下 require 导入 自定义模块 的基本流程
- 将相对路径转为绝对路径, 定位目标文件
- 缓存检测
- 读取目标文件代码
- 包裹为一个函数并执行 (自执行函数)。通过
arguments.callee.toString()查看自执行函数 - 缓存模块的值
- 返回
module.exports的值
.assets/image-20250610110529684.png)
1 | /** |
五、CommonJS 规范
module.exports、exports 以及 require 这些都是 CommonJS 模块化规范中的内容。
而 Node.js 是实现了 CommonJS 模块化规范,二者关系有点像 JavaScript 与 ECMAScript。
CommonJS 规范规定:
-
每个文件就是一个模块,拥有独立的作用域。
-
模块内部通过
1
module.exports
或
1
exports
暴露数据。
module.exports可以暴露任意类型的值(对象、函数、基本数据类型等)。exports实际上是module.exports的一个引用(exports = module.exports = {}),所以通过exports.xxx = value的方式可以为module.exports对象添加属性。但不能直接给exports赋值(如exports = value),否则会切断与module.exports的联系。
-
模块之间通过
require函数导入其他模块暴露出来的数据。
在 Node.js 中遵循 CommonJS 规范进行模块化开发,使得代码的组织和复用更加方便、规范。例如:
模块 A(moduleA.js)
1 | // 暴露一个函数 |
模块 B(moduleB.js)
1 | // 导入模块 A |
这样,通过 module.exports 暴露函数,require 导入并使用,实现了模块间的功能复用和代码组织。
CommonJS 规范在服务器端(如 Node.js 环境)应用广泛,它的同步加载机制(在服务器端,文件读取等操作相对快速且对同步性要求较高)是其特点之一。但在浏览器端,由于同步加载会阻塞页面渲染等问题,后来出现了其他模块化规范(如 AMD、CMD、ES6 模块等)来适应浏览器环境的需求。不过在 Node.js 中,CommonJS 规范依然是核心的模块化方式,并且非常适合服务器端的开发场景,如构建 Web 服务器、处理文件 I/O 等任务时的代码模块化组织。
包管理工具
像极了哆啦A梦的口袋
一、概念介绍
1.1 包是什么
『包』英文单词是 package ,代表了一组特定功能的源码集合
1.2 包管理工具
管理『包』的应用软件,可以对「包」进行 下载安装 , 更新 , 删除 , 上传 等操作
借助包管理工具,可以快速开发项目,提升开发效率
包管理工具是一个通用的概念,很多编程语言都有包管理工具,所以 掌握好包管理工具非常重要
1.3 常用的包管理工具
下面列举了前端常用的包管理工具
npmyarncnpm
二、npm
npm 全称 Node Package Manager ,翻译为中文意思是『Node 的包管理工具』
1 | npm` 是 `node.js` 官方内置的包管理工具,是 `必须要掌握住的工具 |
2.1 npm 的安装
node.js 在安装时会 自动安装 npm ,所以如果你已经安装了 node.js,可以直接使用 npm 可以通过 npm -v 查看版本号测试,如果显示版本号说明安装成功,反之安装失败
2.2 npm 基本使用
2.2.1 初始化
创建一个空目录,然后以此目录作为工作目录 启动命令行工具 ,执行 npm init
npm init 命令的作用是将文件夹初始化为一个『包』,
交互式创建 package.json 文件 package.json 是包的配置文件,每个包都必须要有 package.json
package.json 内容示例
1 | { |
1 | { |
初始化的过程中还有一些注意事项:
- package name( 包名 )不能使用中文、大写,默认值是 文件夹的名称 ,所以文件夹名称也不能使用中文和大写
- version( 版本号 )要求 x.x.x 的形式定义, x 必须是数字,默认值是 1.0.0
- ISC 证书与 MIT 证书功能上是相同的,关于开源证书扩展阅读 http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html
- package.json 可以手动创建与修改
- 使用 npm init -y 或者 npm init --yes 极速创建 package.json
2.2.2 搜索包
搜索包的方式有两种:
- 命令行:npms/search关键字npms/search关键字
- 网站搜索:网址是 https://www.npmjs.com/
经常有同学问,『我怎样才能精准找到我需要的包?』
这个事儿需要大家在实践中不断的积累,通过看文章,看项目去学习去积累。
2.2.3 下载安装包
我们可以通过 npm install 和 npm i 命令安装包。
1 | # 格式 |
运行之后文件夹下会增加两个资源:
node_modules文件夹:存放下载的包package-lock.json:包的锁文件,用来锁定包的版本
安装
uniq之后,uniq就是当前这个包的一个依赖包,有时会简称为依赖。比如我们创建一个包名字为
A,A中安装了包名字是B,我们就说B是A的一个依赖包,也会说A依赖B。
1 | //1.导入 |
1 | D:\Note\code\nodejs\test>npm i uniq |
2.2.4 require 导入 npm 包基本流程
- 在当前文件夹下
node_modules中寻找同名的文件夹。 - 在上级目录中下的
node_modules中寻找同名的文件夹,直至找到磁盘根目录。
1 | //1.导入 |
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 进行全局安装
1 | npm i -g nodemon |
1 | D:\Note\code\nodejs\test>npm i -g nodemon |
全局安装完成之后就可以在命令行的任何位置运行 nodemon 命令。 该命令的作用是 自动重启 node 应用程序。
说明:
- 全局安装的命令不受工作目录位置影响。
- 可以通过
npm root -g查看全局安装包的位置。 - 不是所有的包都适合全局安装,只有全局类的工具才适合,可以通过 查看包的官方文档 来确定安装方式。
2.5.1 修改 Windows 执行策略
.assets/image-20250610120349606.png)
windows 默认不允许 npm 全局命令执行脚本文件,所以需要修改执行策略
- 以 管理员身份 打开 powershell 命令行
.assets/image-20250610120420231.png)
- 键入命令 set-ExecutionPolicy remoteSigned
.assets/image-20250610120442762.png)
-
键入 A 然后敲回车 👌 4. 如果不生效,可以尝试重启 vscode
npm i -g nodemon
D:\Note\code\nodejs\test>npm install -g nodemon
changed 29 packages in 2s
D:\Note\code\nodejs\test>nodemon index.js
‘nodemon’ 不是内部或外部命令,也不是可运行的程序
解决:
遇到的 “nodemon’ 不是内部或外部命令,也不是可运行的程序或批处理文件” 的问题,通常是由于以下几个原因造成的,即使您已经配置了环境变量:
环境变量配置未生效或配置错误:
未重启命令行工具或计算机: 修改环境变量后,需要重新打开命令行工具(如 CMD 或 PowerShell)才能使新的环境变量生效。有时甚至需要重启计算机。
路径错误:
请确保您在系统环境变量
1 Path中添加的路径是
1 npm全局安装模块的正确路径。您可以通过以下命令查看
1 npm的全局安装路径(prefix):
1 npm config get prefix假设该命令返回的路径是
1 C:\Users\YourUsername\AppData\Roaming\npm(这只是一个例子,您的路径可能不同),那么您需要确保这个路径(或者这个路径下的
1 node_modules\.bin目录,具体取决于您的 Node.js 和 npm 版本及配置)被添加到了系统环境变量
1 Path中。
用户变量与系统变量: 建议将 Node.js 和 npm 相关的路径添加到系统变量的
Path中,而不是用户变量的Path中,以确保所有用户和所有终端都能访问。NODE_PATH 环境变量: 有些教程可能会提到配置
NODE_PATH,但NODE_PATH主要用于require模块时的查找路径,对于命令行工具的识别,关键在于Path环境变量。npm 全局安装路径问题:
- 自定义了全局安装路径: 如果您之前通过
npm config set prefix "新的路径"命令修改了 npm 的全局安装路径,那么您需要将这个“新的路径”添加到系统环境变量Path中。 例如,如果您将全局路径设置为D:\nodejs\node_global,那么D:\nodejs\node_global需要在Path环境变量中。node_modules\.bin目录: 全局安装的命令行工具(如 nodemon)的可执行文件通常位于全局安装路径下的node_modules\.bin目录。请确保这个.bin目录也包含在Path环境变量中,或者其父目录已在Path中且 npm 能正确处理。安装问题:
nodemon 未成功全局安装:
虽然提示
1 changed 29 packages,但可能存在某些原因导致
1 nodemon没有正确安装到预期的全局位置。您可以尝试重新全局安装
1 nodemon:
1
2 npm uninstall -g nodemon
npm install -g nodemon权限问题: 在某些情况下,尤其是在 Windows 上,可能需要以管理员权限运行命令行工具来执行全局安装命令
npm install -g nodemon。PowerShell 执行策略 (如果使用 PowerShell):
如果是在 PowerShell 中运行
1 nodemon命令,并且遇到类似“无法加载文件…因为在此系统上禁止运行脚本”的错误,这可能是由于 PowerShell 的执行策略限制。 你可以尝试以管理员身份打开 PowerShell,然后运行以下命令来更改执行策略:
1 Set-ExecutionPolicy RemoteSigned然后按提示输入
1 Y或
1 A。
请注意:
更改执行策略可能会带来安全风险,请了解其含义后再操作。
排查步骤建议:
确认 npm 全局路径:
打开新的命令行窗口,输入npm config get prefix,记录下输出的路径。检查环境变量
Path:
- 打开“我的电脑”或“此电脑” -> 右键“属性” -> “高级系统设置” -> “环境变量”。
- 在“系统变量”下找到名为
Path的变量,双击编辑。- 确认上一步得到的
npm全局路径(例如C:\Users\YourUsername\AppData\Roaming\npm或者您自定义的全局路径如D:\nodejs\node_global)是否已经添加到了Path变量列表中。 如果没有,请添加它。重启命令行/计算机: 修改环境变量后,务必关闭所有已打开的命令行窗口,然后重新打开一个新的,或者直接重启计算机。
重新尝试运行
nodemon:
1
2 nodemon --version
nodemon index.js检查
nodemon是否在全局路径下:
导航到npm config get prefix返回的路径,查看该路径下是否有nodemon或nodemon.cmd文件,以及是否存在node_modules\.bin文件夹,里面是否有nodemon相关文件。尝试使用
npx:
1 npx是 npm 5.2+ 自带的工具,可以运行本地或远程 npm 包中的命令,即使没有全局安装。可以临时用它来测试:
1 npx nodemon index.js如果这个命令能成功运行,说明
1 nodemon本身是好的,问题更可能出在全局环境配置上。
如果以上步骤都无法解决问题,请提供更多信息,例如:
npm config get prefix的输出结果。- 您的环境变量
Path的具体内容截图或文本。- Node.js 和 npm 的版本 (
node -v和npm -v)。
2.5.2 环境变量 Path
Path 是操作系统的一个环境变量,可以设置一些文件夹的路径,在当前工作目录下找不到可执行文件 时,就会在环境变量 Path 的目录中挨个的查找,如果找到则执行,如果没有找到就会报错
.assets/image-20250610120647937.png)
补充说明
- 如果希望某个程序在任何工作目录下都能正常运行,就应该将该程序的所在目录配置到环境变量
Path中。- windows 下查找命令的所在位置
cmd命令行 中执行where nodemon。powershell命令行 执行get-command nodemon。
2.6 安装包依赖
在项目协作中有一个常用的命令就是 npm i,通过该命令可以依据 package.json 和 package-lock.json 的依赖声明安装项目依赖。
1 | npm i |
node_modules 文件夹大多数情况都不会存入版本库。
因为node_modules 非常大 我们不用把它上传到git上,只需要有package-lock.json 就可以了
2.7 安装指定版本的包
项目中可能会遇到版本不匹配的情况,有时就需要安装指定版本的包,可以使用下面的命令。
格式
1 | npm i <包名@版本号> |
示例
1 | npm i jquery@1.11.2 |
2.8 删除依赖
项目中可能需要删除某些不需要的包,可以使用下面的命令:
- 局部删除:
1 | npm uninstall uniq |
- 全局删除:
1 | npm remove -g nodemon |
2.9 配置命令别名
通过配置命令别名可以更简单的执行命令。
- 配置package.json中的 scripts 属性:
1 | { |
- 配置完成之后,可以使用别名执行命令:
1 | npm run server |
注:
start别名比较特别,使用时可以省略run:
1 | npm start |
补充说明:
npm start是项目中常用的一个命令,一般用来启动项目。npm run有自动向上级目录查找的特性,跟require函数也一样。- 对于陌生的项目,我们可以通过查看
scripts属性来参考项目的一些操作。
三、cnpm
3.1 介绍
cnpm 是一个淘宝构建的 npmjs.com 的完整镜像,也称为「淘宝镜像」,网址 https://npmmirror.com/
cnpm 服务器部署在国内阿里云服务器上,可以提高包的下载速度
官方也提供了一个全局工具包 cnpm,操作命令与 npm 大体相同
3.2 安装
我们可以通过 npm 来安装 cnpm 工具
1 | npm install -g cnpm --registry=https://registry.npmmirror.com |
3.3 操作命令
| 功能 | 命令 |
|---|---|
| 初始化 | cnpm init / cnpm init |
| 安装包 | cnpm i uniq cnpm i -S uniq cnpm i -D uniq cnpm i -g nodemon |
| 安装项目依赖 | cnpm i |
| 删除 | cnpm runiq |
3.4 npm 配置淘宝镜像
用 npm 也可以使用淘宝镜像,配置的方式有两种:
- 直接配置
- 工具配置
3.4.1 直接配置
执行如下命令即可完成配置
1 | npm config set registry https://registry.npmmirror.com/ |
3.4.2 工具配置(示例使用 nrm 工具)
1 | 1. **安装 nrm** |
- 修改镜像
1 | nrm use taobao |
- 检查是否配置成功(选做)
1 | npm config list |
检查
registry地址是否为https://registry.npmmirror.com/,如果 是 则表明成功
补充说明:
- 建议使用第二种方式(nrm 配置) 进行镜像配置,因为后续修改起来会比较方便
- 虽然
cnpm可以提高速度,但是npm也可以通过淘宝镜像进行加速,所以npm的使用率还是高于cnpm
四、yarn
4.1 yarn 介绍
yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方网址:https://yarnpkg.com/
4.2 yarn 特点
yarn 官方宣称的一些特点
- 速度超快:yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。同时利用并行下载以最大化资源利用率,因此安装速度更快
- 超级安全:在执行代码之前,yarn 会通过算法校验每个安装包的完整性
- 超级可靠:使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的工作
4.3 yarn 安装
我们可以使用 npm 安装 yarn
1 | npm i -g yarn |
4.4 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) |
4.5 yarn 配置淘宝镜像
可以通过如下命令配置淘宝镜像
1 | yarn config set registry https://registry.npmmirror.com/ |
可以通过 yarn config list 查看 yarn 的配置项
4.6 npm 和 yarn 选择
大家可以根据不同的场景进行选择:
- 个人项目 如果是个人项目,哪个工具都可以,可以根据自己的喜好来选择。
- 公司项目 如果是公司项目要根据项目代码来选择,可以通过锁文件判断项目的包管理工具:
npm的锁文件为package-lock.jsonyarn的锁文件为yarn.lock
包管理工具不要混用,切记,切记,切记
五、管理发布包
5.1 创建与发布
我们可以将自己开发的工具包发布到 npm 服务上,方便自己和其他开发者使用,操作步骤如下:
- 创建文件夹,并创建文件
index.js,在文件中声明函数,使用module.exports暴露。 - npm 初始化工具包,
package.json填写包的信息(包的名字是唯一的)。 - 注册账号 https://www.npmjs.com/signup。
- 激活账号(一定要激活账号)。
- 修改为官方的官方镜像(命令行中运行
nrm use npm)。 - 命令行下
npm login填写相关用户信息。 - 命令行下
npm publish提交包。
5.2 更新包
后续可以对自己发布的包进行更新,操作步骤如下:
- 更新包中的代码。
- 测试代码是否可用。
- 修改
package.json中的版本号。 - 发布更新。
npm publish。
1 | npm publish |
六、扩展内容
在很多语言中都有包管理工具,比如:
| 语言 | 包管理工具 |
|---|---|
| PHP | composer |
| Python | pip |
| Java | maven |
| Go | go mod |
| JavaScript | npm / yarn / cnpm / other |
| Ruby | rubyGems |
除了编程语言领域有包管理工具之外,操作系统层面也存在包管理工具,不过这个包指的是【软件包】
| 操作系统 | 包管理工具 | 网址 |
|---|---|---|
| Centos | yum | https://packages.debian.org/stable/ |
| Ubuntu | apt | https://packages.ubuntu.com/ |
| MacOS | homebrew | https://brew.sh/ |
| Windows | chocolatey | https://chocolatey.org/ |
nvm
一、介绍
nvm 全称 Node Version Manager,顾名思义它是用来管理 node 版本的工具,方便切换不同版本的 Node.js
二、使用
nvm 的使用非常的简单,跟 npm 的使用方法类似
2.1 下载安装
首先先下载 nvm,下载地址 https://github.com/coreybutler/nvm-windows/releases ,选择 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 |
ExpressJS
一、express 介绍
express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架,官方网址:https://www.expressjs.com.cn/
简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)
二、express 使用
2.1 express 下载
express 本身是一个 npm 包,所以可以通过 npm 安装
1 | npm init |
2.2 express 初体验
大家可以按照这个步骤进行操作:
- 创建 JS 文件,键入如下代码
1 | //1. 导入 express |
命令行下执行:
1 | node <文件名> |
访问 http://127.0.0.1:3000/home 可查看结果。
三、express 路由
3.1 什么是路由
官方定义:路由确定了应用程序如何响应客户端对特定端点的请求。
3.2 路由的使用
一个路由的组成有请求方法,路径和回调函数组成。
express 中提供了一系列方法,可以很方便的使用路由,使用格式如下:
1 | app.<method>(path, callback) |
代码示例:
1 | //导入 express |
3.3 获取请求参数
express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式
1 | //导入 express |
3.4 获取路由参数
路由参数指的是 URL 路径中的参数(数据)
1 | app.get('/:id.html', (req, res) => { |
练习
根据路由参数响应歌手的信息
路径结构如下
1 | /singer/1.html |
显示歌手的姓名和图片
1 | { |
四、express 响应设置
express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式
1 | //获取请求的路由规则 |
五、express中间件
5.1 什么是中间件
中间件(Middleware)本质是一个回调函数
中间件函数 可以像路由回调一样访问 请求对象(request),响应对象(response)
5.2 中间件的作用
中间件的作用 就是 使用函数封装公共操作,简化代码
5.3 中间件的类型
- 全局中间件
- 路由中间件
好比是我们去做高铁,我们都是先把行李过一次安检,我们就叫它安检门吧,这个安检门就是属于全局中间件,然后进入这个安检门以后会有很多通道我们需要刷卡进入 这就是路由中间件。
我们必须先检表再上高铁,不然就会产生很多混乱
5.3.1 定义全局中间件
每一个请求 到达服务端之后 都会执行全局中间件函数
声明中间件函数
1 | let recordMiddleware = function(request, response, next){ |
.assets/image-20250610174956850.png)
应用中间件
1 | app.use(recordMiddleware); |
声明时可以直接将匿名函数传递给 use
1 | app.use(function (request, response, next) { |
5.3.2 多个全局中间件
express 允许使用 app.use() 定义多个全局中间件
1 | app.use(function (request, response, next) { |
5.3.3 定义路由中间件
如果只需要对某一些路由进行功能封装,则就需要路由中间件
调用格式如下:
1 | app.get('/路径', '中间件函数', (request, response)=>{ |
5.4 静态资源中间件
express 内置处理静态资源的中间件
1 | //引入express框架 |
注意事项:
index.html文件为默认打开的资源- 如果静态资源与路由规则同时匹配,谁先匹配谁就响应
- 路由响应动态资源,静态资源中间件响应静态资源
5.5 获取请求体数据 body - parser
express 可以使用 body - parser 包处理请求体
第一步:安装
1 | npm i body - parser |
第二步:导入 body - parser 包
1 | const bodyParser = require('body - parser'); |
第三步:获取中间件函数
1 | // 处理 querystring 格式的请求体 |
第四步:设置路由中间件,然后使用 request.body 来获取请求体数据
1 | app.post('/login', urlParser, (request, response) => { |
获取到的请求体数据:
1 | [Object: null prototype] { username: 'admin', userpass: '123456' } |
六、Router
6.1 什么是 Router
express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。
6.2 Router 作用
对路由进行模块化,更好的管理路由。
6.3 Router 使用
- 创建独立的
JS文件(homeRouter.js)
1 | t//1. 导入 express |
- 主文件
1 | const express = require('express'); |
七、EJS 模板引擎
7.1 什么是模板引擎
模板引擎是分离用户界面和业务数据的一种技术。
7.2 什么是 EJS
EJS 是一个高效的 Javascript 的模板引擎。
- 官网: https://ejs.co/
- 中文站: https://ejs.bootcss.com/
7.3 EJS 初体验
下载安装 EJS
1 | npm i ejs --save |
代码示例
1 | // 1.引入ejs |
命令行下运行
7.4 EJS常用语法
执行JS代码
1 | <% code %> |
输出转义的数据到模板上
1 | <%= code %> |
输出非转义的数据到模板上
1 |
|
MongoDB
一、简介
1.1 MongoDB是什么
MongoDB是一个基于分布式文件存储的数据库,官方地址 https://www.mongodb.com/
1.2 数据库是什么
数据库(DataBase)是按照数据结构来组织、存储和管理数据的<应用程序>
1.3 数据库的作用
数据库的主要作用就是<管理数据>,对数据进行<增(c)、删(d)、改(u)、查(r)>
1.4 数据库管理数据的特点
相比于纯文件管理数据,数据库管理数据有如下特点:
- 速度更快
- 扩展性更强
- 安全性更强
1.5 为什么选择 MongoDB
操作语法与 JavaScript 类似,容易上手,学习成本低
二、核心概念
Mongodb中有三个重要概念需要掌握
- 数据库(database):数据库是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存放很多集合
- 集合(collection):集合类似于JS中的数组,在集合中可以存放很多文档
- 文档(document):文档是数据库中的最小单位,类似于JS中的对象
大家可以通过 JSON 文件来理解 Mongodb 中的概念
- 一个 JSON 文件 好比是一个 数据库,一个 Mongodb 服务下可以有 N 个数据库
- JSON 文件中的一级属性的数组值 好比是 集合
- 数组中的对象好比是 文档
- 对象中的属性有时也称之为 字段
一般情况下
- 一个项目使用一个数据库
- 一个集合会存储同一种类型的数据
三、下载安装与启动
下载地址: https://www.mongodb.com/try/download/community 建议选择 zip 类型,通用性更强
配置步骤如下:
1> 将压缩包移动到 C:\Program Files 下,然后解压
2> 创建 C:\data\db 目录,mongodb 会将数据默认保存在这个文件夹
3> 以 mongodb 中 bin 目录作为工作目录,启动命令行
4> 运行命令 mongod
会话控制
一、介绍
所谓会话控制就是 对会话进行控制
HTTP 是一种无状态的协议,它没有办法区分多次的请求是否来自于同一个客户端, 无法区分用户
而产品中又大量存在的这样的需求, 所以我们需要通过 会话控制 来解决该问题
常见的会话控制技术有三种:
- cookie
- session
- token
二、cookie
2.1 cookie 是什么
cookie 是 HTTP 服务器发送到用户浏览器并保存在本地的一小块数据
cookie 是保存在浏览器端的一小块数据
cookie 是按照域名划分保存的
简单示例:
| 域名 | cookie |
|---|---|
| https://www.baidu.com | a=100; b=200 |
| https://www.bilibili.com | xid=1020abce121; hm=112411213 |
| jd.com | x=100; ocw=12414cce |
2.2 cookie 的特点
浏览器向服务器发送请求时,会自动将 当前域名下 可用的 cookie 设置在请求头中,然后传递给服务器
这个请求头的名字也叫 cookie ,所以将 cookie 理解为一个 HTTP 的请求头也是可以的 2.3 cookie 的运行流程 填写账号和密码校验身份,校验通过后下发 cookie
.assets/image-20250610180549565.png)
有了 cookie 之后,后续向服务器发送请求时,就会自动携带 cookie
.assets/image-20250610180611114.png)
三、Session
3.1 Session 是什么
Session 是保存在服务器端的一块儿数据,保存当前访问用户的相关信息。
3.2 Session 的作用
实现会话控制,可以识别用户的身份,快速获取当前用户的相关信息。
3.3 Session 运行流程
- 用户填写账号和密码校验身份,校验通过后创建
session信息。 - 服务器将
session_id的值通过响应头返回给浏览器。 - 当浏览器再次发送请求时,会将
session_id携带在请求头中。 - 服务器接收到请求后,根据
session_id找到对应的session信息,从而知道当前用户的身份等相关信息。
.assets/image-20250610180718738.png)
有了 cookie,下次发送请求时会自动携带 cookie,服务器通过 cookie 中的 session_id 的值确定用 户的身份
.assets/image-20250610180739400.png)
类似比喻:好比去理发店,一般会有会员说是如果不充值35 充值25且这一次免费,充值玩后它会给你一张卡,然后他会再它的笔记本上记录信息 以后要剪头发只要去笔记本里看看有没有你的信息即可。
四、session 和 cookie 的区别
cookie 和 session 的区别主要有如下几点:
1. 存在的位置
- cookie:浏览器端
- session:服务端
2. 安全性
- cookie 是以明文的方式存放在客户端的,安全性相对较低
- session 存放于服务器中,所以安全性相对较好
3. 网络传输量
- cookie 设置内容过多会增大报文体积,会影响传输效率
- session 数据存储在服务器,只是通过 cookie 传递 id,所以不影响传输效率
4. 存储限制
- 浏览器限制单个 cookie 保存的数据不能超过 4K,且单个域名下的存储数量也有限制
- session 数据存储在服务器中,所以没有这些限制
