Node.js

Node.js是一个跨平台的JavaScript运行环境,是开发者可以开发服务端的JavaScript应用程序

Node.js为何能执行JS?

  • 浏览器能运行js代码,依靠的是内核中的V8引擎
  • Node.js是基于Chrome V8引擎进行封装
  • 都支持ECMAScript标准语法,Node.js有独立的API
  • Node.js没有Dom和Bom对象

node.js的注意事项。

不能够使用bom和dom的API。但是可以使用console和定时器的API。

node.js有一个顶级对象:global。再node2020中引入了globalthis,他指向global对象。

buffer

buffer是一个类似于数组的对象,用于表示固定长度的字节序列

本质是一段内存空间,用来处理二进制。

特点

  1. Buffer大小固定且无法调整
  2. Buffer性能较好,直接对计算机内存进行操作
  3. 每一个元素的大小为一字节

使用

创建Buffer

1
2
3
4
5
6
7
8
9
10
11
12
// 使用Buffer.alloc()函数
var buffer = Buffer.alloc(10)
console.log(buffer);

// 使用Buffer.allocUnsafe()函数,可能会存在旧数据
// 内存空间是可以重复使用的,alloc方法会对内存空间重新清0,但是allocUnsafe不会,所以可能会有旧数据
var buffer_unsafe = Buffer.allocUnsafe(1000);
console.log(buffer_unsafe)

// 使用Buffer.from()函数,传入一个字符串或者数组
var buffer_from = Buffer.from("hello");
console.log(buffer_from)

Buffer的相关操作

1
2
3
4
5
6
7
8
9
10
// Buffer与字符串的转换
var buffer_from_array = Buffer.from([105,108,111,118,101,121,111,117]);
// 调用toString()方法将Buffer转换成字符串
console.log(buffer_from_array.toString())

// 操作buffer中的数据
var buffer_from = Buffer.from("hello");
console.log(buffer_from[0]); // 下标,取得十进制数据
// 可以使用toString(2)将数据转换成2禁止
console.log(buffer_from[0].toString(2))

注意事项

1
2
3
4
5
6
7
// 8位二进制存储的最大十进制数是255,如果数值大于255(数据超出了八位),就会舍弃高位数据
var buffer = Buffer.alloc(10);
buffer[0] = 166
console.log(buffer[0])

buffer[0] = 256 // 此时更改为一个大于255的数据
console.log(buffer[0])

fs模块

fs(File System),可以用来操作计算机上磁盘文件,实现文件的读写操作。

1
2
3
4
5
6
7
8
9
10
11
// 1.引入FS模块
const fs = require('fs')
// 2.创建一个本地文件 3.写入信息
fs.writeFile("./test.txt","Hello world",function (res){
// 如果写入失败了,那么res就是一个错误对象,如果写入成功了,res为null
if(!res){
console.log("success")
} else {
console.log("error");
}
})

fs的工作模式

fs写入文件默认是异步的,写入文件的操作会交给其他线程完成,主线程不会等待IO操作。等到写入完成后,将回调函数压入到队列中,等待主线程执行完毕再执行回调函数。

fs写入文件的同步模式

1
2
3
4
5
// fs的同步写入
// 1.引入fs模块
const fs = require('fs')
// 2.同步写入文件
fs.writeFileSync('./test.txt','test')

fs文件追加写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// fs的追加
// 1.引入fs模块
const fs = require('fs')
// 调用appendFile
fs.appendFile('./test.txt',"hello world",function (res){
if(!res){
console.log('追加文件成功');
} else {
console.log('写入文件失败');
}
})

// 方法2
// 追加一个配置对象,即可让writeFile实现追加写入的效果
fs.writeFile('./test.txt',"hello world",{flag:'a'},function (res){
if(!res){
console.log('追加文件成功');
} else {
console.log('写入文件失败');
}
})

fs流式写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 流式写入
const fs = require('fs')

// 创建写入流对象
const ws = fs.createWriteStream('./test.txt')
// write
ws.write("hello world")
ws.write("hello world")
ws.write("hello world")
ws.write("hello world")
ws.write("hello world")

// 关闭流
ws.close()

// 流式传输更适用与写入频率更高的场景,不用频繁的创建流
// 也适合大文件写入

fs文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 使用fs模块读取文件,并把文件内容打印到控制台
// 1.导入fs模块
const fs = require('fs')
// 2.异步读取
fs.readFile('./test.txt',function(err,data){
if(err){
console.log('读取失败');
}

console.log(data.toString());
})

// 3.同步读取
let data = fs.readFileSync('./test.txt')
console.log(data.toString());

fs文件流式读取

1
2
3
4
5
6
7
8
9
10
11
12
13
// 流式读取
// 1.导入fs模块
const fs = require('fs')
// 2.创建读取流
const rs = fs.createReadStream('./test.txt')
// 3.绑定data事件 chunk文件的一块(分块读取)
rs.on('data',chunk => {
console.log(chunk.length);
})
// 4.绑定end事件
rs.on('end',()=>{
console.log('读取文件结束');
})

fs文件重命名和移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 文件重命名和移动
// 1.导入fs模块
const fs = require('fs')
// 2.调用rename
fs.rename('./test.txt','./文件.txt',err => {
if(err){
console.log('重命名失败');
}
console.log('success');
})

// 3.文件的移动
fs.rename('./文件.txt','./data/文件.txt',err => {
if(err){
console.log('移动文件失败');
}
console.log('success');
})

fs文件删除

1
2
3
4
5
6
7
8
9
10
11
12
// 文件删除
// 1.导入fs模块
const fs = require('fs')
// 2.调用unlink 同步方法:unlinkSync
fs.unlink('./data/文件.txt',()=>{

})

// 2.调用rm方法 同步方法:rmSync
fs.rm('./创建vue对象.html',()=>{

})

fs文件夹操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 文件夹操作
// 1.导入fs模块
const fs = require('fs')
// 创建文件夹
fs.mkdir('./data',()=>{})
// 支持递归创建
fs.mkdir('./data/a/b',{recursive:true},()=>{})
// 读取文件夹
fs.readdir('./',(err,data)=>{
// 返回数组
console.log(data);
})
// 删除文件夹
fs.rmdir('./1',(err)=>{
console.log(err);
})

// 递归删除
fs.rmdir('./data',{recursive:true},(err)=>{
console.log(err);
})

fs查看资源状态

1
2
3
4
5
6
7
8
9
10
11
// 查看资源状态
// 1.导入fs模块
const fs = require('fs')
// 2.调用stat
fs.stat('./vue.js',(err,data)=>{
console.log(data);
// 是否文件
console.log(data.isFile());
// 是否文件夹
console.log(data.isDirectory());
})

path模块

Node.is 代码中,相对路径是根据终端所在路径来查找的,可能无法找到你想要的文件

建议:在Node.js的代码中,使用绝对路径

如何避免这个问题?

可以使用__dirname来获取模块的路径

__dirname:获取当前模块的绝对路径

不建议使用字符串拼接的方式来拼接路径,可以使用path.resolve和path.join函数来拼接。

Http模块

1.什么是HTTP协议?

http协议,超文本传输协议

是互联网使用最广泛的协议之一,是客户端和服务端通信的一种约定。

2.HTTP报文

请求报文结构

请求行的组成部分

  • 请求方式,如GET,POST

  • GET 用于获取资源

  • POST 用于新增资源

  • DELETE 用于删除资源

  • PUT/PATCH 用于修改资源

  • url

  • 协议及版本

请求头

为一个键值对结构,冒号之前的为键,冒号之后为值。记录了客户端请求的一些内容

请求体

请求体的格式非常多,可以为json,或者其他格式。

响应报文结构

响应行的组成部分

  • 协议及版本

  • 相应状态码

  • 200 成功

  • 403 拒绝访问

  • 404 资源未找到

  • 500 服务器端错误

  • 响应状态的描述

响应头的组成部分

记录了服务的相应的一些信息

3.HTTP模块

创建HTTP服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 导入http模块
const http = require('http')

// 创建服务对象
const server = http.createServer((req, res)=>{
// res.end("hello http server");// 设置响应体
// 如果出现中文乱码问题:可以通过设置响应头的方式解决
res.setHeader("content-type",'text/html;charset=utf-8');
res.end('你好');
});

// 监听端口,启动服务

server.listen(9000,()=>{
console.log("服务已经启动");
})

提取请求报文内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const http = require('http')

const server = http.createServer((req, res)=>{
// 获取请求方法
console.log(req.method)
// 获取浏览器的url
console.log(req.url)
// 获取http协议的版本
console.log(req.httpVersion)
// 获取请求头
console.log(req.headers)
// 获取请求体
// 1.定义接受请求体参数对象
let reqBody = '';
// 2.绑定data事件,用于接受req流里的数据
req.on('data',chunk => {
reqBody += chunk;
})
// 3.绑定end事件,数据读取完毕执行
req.on('end',()=>{
console.log(reqBody)
})
res.end()
})

server.listen('9000',()=>{
console.log('服务启动')
})

如果需要解析url,可以使用url模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const http = require('http')

const url = require('url')

const server = http.createServer((req, res)=>{
let url = new URL('https://www.bilibili.com/video/BV1gM411W7ex?p=52&vd_source=a6904af2f8e9663e9d5addf564fa5351')
console.log(url)
console.log(req)
res.end();
})

server.listen('9000',()=>{
console.log('服务启动')
})

设置响应体内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const http = require('http')

const server = http.createServer((req, res)=>{
// 1.设置响应状态码
res.statusCode = 201
// 2.设置响应头
res.setHeader("myheader","head")
// 3.设置响应体
res.write("hello")

res.end();
})

server.listen('9000',()=>{
console.log('服务启动')
})

如何实现网页引入外部资源?

通过前面的学习,我们已经知道,通过在响应体里面设置返回的H5代码,可以让浏览器显示网页。

如果这个h5页面包含了js,css的代码,那么可以直接渲染出来。

但是如果我们使用引入文件的方式,这个时候还能正常的加载资源文件吗?

答案是否定的。

为什么?

因为我们现在浏览器对服务器发出来的请求,执行的是监听的回调函数。这个函数目前的逻辑只会返回h5代码。

我们请求css,js的代码获取的返回内容,都是这个h5,自然无法渲染。

  1. 高复用性
  2. 高维护性

Node.js模块化

定义:在Node.js中,每个文件都被视为是一个单独的模块

概念:项目是由很多个模块组成的

好处:提高代码复用性,按需加载,独立作用域

使用:需要标准语法导出和导入进行使用

CommonJs标准

模块化示例

对外暴露函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function run(){
console.log("跑步")
}

function jump(){
console.log("跳跃")
}

// 可以使用module.exports将两个函数暴露出去
module.exports = {
run:run,
jump:jump
}

外部导入模块

对于内置模块,可以直接使用模块名导入

如果是自定义模块,通过写模块文件路径来导入

1
2
3
4
// 导入自定义file02模块
const file02 = require('./file02')
// 导入内置模块
const path = require('path')

模块化数据的暴露

方式1:
1
2
3
4
5
// 可以使用module.exports将两个函数暴露出去
module.exports = {
run:run,
jump:jump
}
方式2:
1
2
3
// 也可以使用exports将函数暴露出去
exports.run = run
exports.jump = jump

模块化暴露数据的注意事项

1.可以使用module.exports暴露任何形式的数据
1
2
module.exports = 123
module.exports = 'iloveyou'
2.不能使用exports = value的形式暴露数据

module.exports,exports的关系如下:

1
module.exports = exports = {}

此处require获取的module.exports的值,修改exports对象不会影响到module.exports的值

1
const file02 = require('./file02')

导入文件模块

  1. require模块时使用相对路径,./ 和 ../ 不能省略
  2. 导入js文件和json文件时,可以省略后缀。如果省略后缀,js和json文件同名了,优先导入js文件
  3. 如果导入其他类型的文件,按照js文件处理
  4. 如果导入的是一个文件夹,则会优先去检测package.json文件的main属性对应的文件,如果找不到,就会报错。如果main属性不存在,或者package.json不存在,则会尝试导入index.js或者index.json,不存在就报错
  5. 导入node.js内置模块不需要加../ 或者 ./

require导入模块的基本流程

  1. 接受相对路径,转换成绝对路径
  2. 缓存查找是否存在,存在直接返回,不存在往下执行
  3. 读取目标文件的代码
  4. 包裹为一个函数并执行
  5. 添加到缓存
  6. 返回module.exports

ECMAScript标准

导出:export default {}

导入:import 变量名 from ‘模块名或路径’

注意:Node.js默认支持CommonJS标准语法

如需要使用ECMAScript语法,在运行模块所在文件夹新建package.json文件,并设置

1
2
3
{
"type": "module"
}

案例

已配置package.json文件

utils.js,被导入的文件

1
2
3
4
5
const info = '孤岛'

export default {
name: info
}

index.js, 导入utils模块的文件

1
2
3
import name from './utils.js'

console.log(name)

命名导出和导入

导出:export 修饰定义语句

导入:import {同名变量} from ‘模块名或路径’

如何选择默认导出和命名导出?

  • 按需加载,使用命名导出和导入
  • 全部加载,使用默认导出和导入

案例

utils.js,被导入的文件

1
2
3
4
5
6
7
8
9
10
export const info = '孤岛'

function log(){
console.log(1)
}

export default {
name: info,
log:log
}

index.js,导入utils的文件

1
2
3
4
5
6
7
// 命名导入
import {info} from './utils.js'
console.log(info)

// 默认导入
import obj from './utils.js'
console.log(obj)

Node.js的包

什么是包?

将模块,代码,其他资料聚合成文件夹

包分为哪两类

  • 项目包:编写项目代码的文件夹
  • 软件包:封装工具和方法供开发者使用

package.json 文件的作用?

记录软件包的名字,作者,入口文件等信息

导入一个包文件夹的时候,导入的是哪个文件?

默认 index.js 文件,或者 main 属性指定的文件

npm-软件包管理器

npm 是 Node.js 标准的软件包管理器。
在 2017 年1月时,npm 仓库中就已有超过 350000 个软件包,这使其成为世界上最大的单一语言代码仓库,并且可以确定几乎有可用于一切的软件包。
它起初是作为下载和管理 Node.js 包依赖的方式,但其现在也已成为前端JavaScript 中使用的工具。

切换到需要初始化的包路径下,执行如下命令。

1
npm init

注意事项:

  1. 填写的包名不能使用中文或者大写字母,只能使用友好的URL字符,默认值是文件夹的名称,所以文件夹的名字也不能是大写和中文。
  2. package.json支持用户手动创建和修改
  3. 可以是用快速创建的命令创建package.json 全部问题按照默认值回答
1
2
npm init --yes
npm init -y

搜索工具包

方式1:使用搜索命令

1
npm search math

方式2:进入网址搜索https://www.npmjs.com/

安装包

注意:规范的操作应该在安装包之前先初始化包

1
2
3
4
npm install uniq
# uniq为包名
# 也可以使用简写
npm i uniq

命令运行之后会多出两个资源

  1. node_modules:用于存放下载的包
  2. package_lock.json:用于锁定包的版本

require导入npm包的基本流程

  1. 在当前文件夹下node_modules寻找同名文件夹
  2. 在上级的node_modules寻找同名文件夹,直至找到磁盘根目录

开发依赖与生产依赖

  • 开发依赖是只在开发环境用到的依赖
  • 生产依赖是实在开发环境和生产环境都需要用到的依赖
1
2
3
4
5
6
7
# 安装生产依赖
npm install -S uniq
npm install --save uniq

# 安装开发依赖
npm install -D less
npm install --save-dev less

npm的全局安装

命令:npm i -g nodemon

我们可以使用-g选项来执行全局安装操作。

全局安装的包,安装时不收操作目录的影响。

全局安装的包,安装完之后保存到一个单独的目录。可以使用如下命令查看存放位置:

1
node root -g

不是所有的包都是和全局安装,只有全局类的工具才适合

npm安装包的所有依赖

1
2
npm install 
npm i

依据package.json和package-lock.json下载项目所需要的依赖

注意:node_modules大多数情况不进入版本控制(git)

npm安装指定版本的包与npm删除包

npm安装指定版本包

1
2
npm i <package@version>
npm i jquery@2.2.1

安装指定版本的包之后,将会修改package-lock.json对应依赖的版本号。

npm删除指定的包

1
2
npm remove <package>
npm r <package>

执行删除命令之后,也会修改对应的package-lock.json文件

配置命令的别名

通过配置别名可以更简单的执行命令,简化命令的编写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "package_01",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"server": "node ./removeSame.js",
"start": "node ./removeSame.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"uniq": "^1.0.1"
}
}

通过在package.json的scripts属性中,配置属性即可完成别名的配置。通过npm run ***即可执行命令

npm start 可以省略run,npm start一般用来启动项目

npm run具有向上级目录查找命令的特性。

使用nrm模块管理下载镜像源

安装nrm模块

1
npm install -g nrm

使用nrm切换镜像源

1
nrm use taobao

查看镜像源

1
nrm ls

检查镜像是否配置成功

1
npm config list

yarn-包管理工具

yarn 官方宣称的一些特点

  1. 速度更快,yarn会将每一个下载过的包缓存起来,下次使用无需下载,同时利用并行下载技术加速下载
  2. 更安全,在执行代码之前,yarn会根据算法去验证每个安装包的完整性
  3. 使用详细,简洁的锁文件格式和明确的安装算法,yarn能够保证在不同系统上无差异的工作

yarn安装

可以通过npm命令安装yarn

1
npm i -g yarn 

yarn常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 初始化
yarn init
yarn init -y
# 安装生产依赖
yarn add uniq
# 安装开发依赖
yarn add less --dev
# 删除依赖
yarn remove less
# 安装全局依赖
yarm global add nodemon
# 安装项目依赖
yarn
# 启动脚本
yarn <server># 不需要添加run

yarn配置镜像源

1
2
3
4
# 查看镜像源
yarn config list
# 设置镜像
yarn config set registry <location>

express模块

什么是express?

是一个基于node.js的平台的极简的,灵活的web框架。

express是一个工具包,封装了很多的功能,便于我们开发web服务

express使用

1.安装express

1
node install express

2.导入express模块

1
const express = require('express')

3.创建应用

1
const app = express()

4.创建路由,编写逻辑

1
2
3
4
app.get('/index',(req,res)=>{
// 具体的接口逻辑
console.log('请求成功')
})

5.监听端口,启动服务

1
2
3
app.listen("8000",()=>{
// 服务启动之后会执行的逻辑
})

什么是路由?

路由确定了应用程序如何响应客户端对特定端点的请求。

路由的使用

路由一般有三部分组成

  • 请求方法,请求路径,回调函数

获取请求参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 导入express模块
const express = require('express')
// 创建应用对象
const app = express()
// 创建路由
app.get("/home",(req,res)=>{
// 获取请求参数
// 获取请求头
console.log(req.get("host"));
// 获取请求路径
console.log(req.path)
// 获取查询条件
console.log(req.query);
// 获取ip
console.log(req.ip);
res.end("hello express")
})
// 监听端口,返回结果
app.listen("8000",()=>{
console.log("监听端口8000,服务启动成功")
})

获取路由参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 导入express模块
const express = require('express')
// 创建应用对象
const app = express()
// 创建路由
app.get("/home/:id",(req,res)=>{
// 获取路由参数
console.log(req.params.id)
res.end("hello express")
})
// 监听端口,返回结果
app.listen("8000",()=>{
console.log("监听端口8000,服务启动成功")
})

一般响应设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 导入express模块
const express = require('express')
// 创建应用对象
const app = express()
// 创建路由
app.get("/home",(req,res)=>{
// 设置一般响应
// 设置状态码
res.status(404)
// 设置响应头
res.set('aaa','bbb')
// 设置响应体
// 此处中文不会乱码,是因为send方法自动设置Content-Type: text/html; charset=utf-8的响应头
res.send("hhhh啊啊啊")
})
// 监听端口,返回结果
app.listen("8000",()=>{
console.log("监听端口8000,服务启动成功")
})

其他响应设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 导入express模块
const express = require('express')
// 引入path模块
const path = require('path')
// 创建应用对象
const app = express()
// 创建路由
app.get("/home",(req,res)=>{
// 重定向
// res.redirect("https://www.baidu.com")
// 下载响应
// res.download(path.resolve('test.html'))
// 响应json
// res.json({abc:123})
// 响应文件内容
res.sendFile(path.resolve('test.html'))
})
// 监听端口,返回结果
app.listen("8000",()=>{
console.log("监听端口8000,服务启动成功")
})

中间件

什么是中间件

中间件本质是一个回调函数

中间件函数可以像路由一样,访问到request,response对象,进行操作

中间件的作用

可以封装通用的逻辑,简化代码的编写

中间件的类型

全局中间件

每一个请求到达服务端之后,在执行路由代码之前都会执行的中间件

路由中间件

每一个请求到达服务端之后,会调用对应的路由中间件执行

全局中间件的实践

需求:使用全局中间件实现一个记录访问日志的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 引入fs模块
const fs = require('fs')
// 导入express模块
const express = require('express')
// 引入path模块
const path = require('path')

// 声明一个中间件函数
// next变量指向后续的路由函数或者中间件回调
function recordAccessAddress(req, res, next) {
let {url, ip} = req
// 全局中间件需求,记录每一次请求的ip地址
fs.appendFileSync(path.resolve('access.log'), `${url},${ip}\r\n`)
// 调用next
next()
}

// 创建应用对象
const app = express()

// 使用中间件函数
app.use(recordAccessAddress)

// 创建路由
app.get("/index", (req, res) => {

res.json(
{
msg: "index请求成功"
}
)
})

app.get("/admin", (req, res) => {
res.json(
{
msg: "admin请求成功"
}
)
})

app.get("/*", (req, res) => {
res.json(
{
msg: "404"
}
)
})
// 监听端口,返回结果
app.listen("8000", () => {
console.log("监听端口8000,服务启动成功")
})

路由中间件实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 引入fs模块
const fs = require('fs')
// 导入express模块
const express = require('express')
// 引入path模块
const path = require('path')

// 创建应用对象
const app = express()

// 创建路由中间件
let checkCode = function (req,res,next) {
if(req.query.code === '521'){
next()
} else {
res.send('暗号错误')
}
}

// 创建路由,将路由中间件传入路由
app.get("/index",checkCode, (req, res) => {
res.json(
{
msg: "index请求成功"
}
)
})

app.get("/admin",checkCode, (req, res) => {
res.json(
{
msg: "admin请求成功"
}
)
})

app.get("/*", (req, res) => {
res.json(
{
msg: "404"
}
)
})
// 监听端口,返回结果
app.listen("8000", () => {
console.log("监听端口8000,服务启动成功")
})

静态资源中间件设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 引入fs模块
const fs = require('fs')
// 导入express模块
const express = require('express')
// 引入path模块
const path = require('path')

// 创建应用对象
const app = express()

// 创建静态资源中间件
app.use(express.static(path.resolve("./public")))

// 创建路由
app.get("/index", (req, res) => {
res.json(
{
msg: "index请求成功"
}
)
})

app.get("/admin", (req, res) => {
res.json(
{
msg: "admin请求成功"
}
)
})

app.get("/*", (req, res) => {
res.json(
{
msg: "404"
}
)
})
// 监听端口,返回结果
app.listen("8000", () => {
console.log("监听端口8000,服务启动成功")
})

静态资源中间件注意事项

  1. 当查询条件为“/”时,静态资源中间件默认寻找index.html返回
  2. 当存在“/”路由,静态资源又存在index.html文件时,谁先匹配上响应谁
  3. 路由响应动态资源,静态资源让静态资源中间件处理