Nodejs 第二十七章 动静分离
Nodejs 第二十七章 动静分离
什么是动静分离?
动静分离(Dynamic and Static Separation)是一种常见的架构模式,旨在优化资源管理和提高网站或应用的性能和可维护性。动静分离主要指的是将动态内容(经常变化或依赖于用户请求的内容)和静态内容(如样式表、脚本、图片等不经常更改的资源)分开处理和存储。
动静分离的目的
- 性能优化:通过分离动态和静态内容,可以针对性地优化两种资源的加载和缓存策略。静态内容可以通过CDN(内容分发网络)进行分发,利用缓存机制减少服务器的负担,加快内容的加载速度。
- 提高可维护性:动静分离简化了应用的管理。静态资源由于不依赖于业务逻辑,可以独立于应用进行更新和维护,而不影响动态内容的处理。
- 成本效率:静态内容的存储和传输成本通常低于动态内容。通过将静态内容分发到CDN,可以减少主服务器的带宽和计算资源消耗,从而降低成本。
- 缩短开发时间:动静分离允许前端开发者和后端开发者更加独立地工作,前端开发者可以专注于UI/UX的改进,而后端开发者可以专注于业务逻辑和API的开发。
实现动静分离的方法
- 使用CDN:将图片、CSS文件、JavaScript文件等静态资源上传到CDN,利用CDN的全球分发优势来加速内容的加载。
- 配置Web服务器:在Web服务器(如Nginx, Apache)中配置URL重写规则,将请求分发到对应的动态应用服务器或静态资源服务器。
- 前后端分离:将前端应用(通常包括HTML页面和静态资源)与后端API服务分离部署。前端通过Ajax或Fetch等技术与后端进行数据交互,实现完全的前后端分离。
- 使用缓存策略:为静态资源设置较长的缓存时间,减少重复请求的次数,而动态内容则根据内容更新频率调整缓存策略。
应用场景
动静分离在多种应用场景中非常有用,特别是在高流量网站和大规模Web应用中,如电商平台、新闻门户、社交网络等。通过动静分离,这些应用能够有效地管理大量的用户请求,提供快速的响应速度,同时降低服务器的压力。
CDN(内容分发网络)概述
- 在前面有讲到
CDN
来实现动静分离,那什么又是CDN
呢? - CDN(Content Delivery Network)是一种分布式网络服务,它通过将内容缓存到全球各地的多个数据中心来加速互联网内容的加载速度。CDN 的核心目的是通过地理上更靠近用户的服务器提供内容,从而减少数据传输的延迟和带宽消耗,提升用户访问速度和网站的整体性能。
CDN的工作原理
当用户尝试访问使用CDN服务的网站时,以下步骤通常会发生:
- DNS 解析:用户的浏览器首先解析请求的URL中的域名,用来确定对应的IP地址。在使用CDN的情况下,这个DNS解析请求会被指向一个CDN的DNS服务器。
- 选择最佳节点:CDN的DNS服务器将评估请求者的地理位置(距离近总会快一点)和CDN网络中各个缓存节点的健康状况、负载情况等,选择最佳的节点来响应用户的请求。
- 内容交付:如果所选的CDN节点拥有请求的内容的缓存副本,它将直接返回给用户。如果没有,CDN节点会从原始服务器或更近的缓存节点获取内容,缓存它,并在响应用户请求的同时,保存一份副本以供未来请求使用。
代码实现
初始化项目
- npm init -y:生成package.json文件,其中type设置为module模式,以便使用ESM语法
- 创建static文件夹:用来存放静态资源
- 创建index.js文件:编写动静分离代码的地方
静态资源处理
-
我们首先,先来实现一个静态资源的存储和处理
-
这个步骤其实是较为简单的,我们按部就班的用http的起一个服务,然后读取到静态资源内的内容塞进去就结束了。
-
当然,在这个过程中,我们还需要进行额外的边界处理,比如说判断传递过来的路径究竟是不是要读取静态资源的,不是则返回404的响应头,并告诉用户读取的该url内容是错误的,你路径错啦~
如果是的话,当然就返回内容咯
-
但这里有一个需要注意的点,就是写入响应头的内容中,
Content-Type
这里要进行正确的返回,则返回类型要写对,比如返回的是纯文本,就是"text/plain"
,但如果是图片什么的,就没准是png等等其他的了。这个类型叫做mime类型,而Node社区有提供一个第三方库,能够让我们直接把用户传递过来的url丢进去对应的API中就返回正确的mime类型,非常省心第三方库安装:
npm i mime
-
import http from "node:http"
import fs from "node:fs"
import path from "node:path"
import mime from "mime"
http.createServer((req, res) => {
// 获取传给服务器的地址和请求方式
const { url, method } = req
// console.log(url); url返回localhost:端口/中的包括斜杠的后面内容
// 筛选出静态文件夹static的情况(只存在于GET请求中)
if (url.startsWith('/static') && method === 'GET') {
// 获取上传的路径
const filePath = path.join(process.cwd(), url)
// 获取对应的mime类型
const mimeType = mime.getType(filePath)
// 读取文件内容
fs.readFile(filePath, (err, data) => {
// 处理错误的边界情况
if (err) {
res.writeHead(404, {
'content-Type': "text/plain"// 设置响应头为纯文本类型
})
res.end('报错了嘞:', err)
} else {
res.writeHead(200, {
"content-Type": mimeType, // 设置响应头为对应的MIME类型
"cache-Control": "public, max-age=3600" // 设置缓存控制头(缓存一小时)
})
res.end(data)
}
})
}
}).listen(3000, () => {
console.log("3000端口已启动");
})
-
同时请注意我们这行代码:
"cache-Control": "public, max-age=3600" // 设置缓存控制头(缓存一小时)
.这将我们的内容进行了缓存,缓存在浏览器里了,当我们重新开一个页面进行请求的时候,因为这行缓存代码,我们将不会重新执行一遍代码,而是直接从浏览器缓存中进行调用(不经过服务器)- 这缓存分为内存缓存跟硬盘缓存(浏览器会自动选择这个策略),当我们在浏览器看的时候,可能会缓存到内存中,而当我们关掉浏览器,就有可能缓存到电脑的硬盘当中了
-
根据URL地址的判定中,能够看到我们起的3000端口服务成功辨认了
/static
静态文件夹- html、css、png等三种类型成功同时显示
- 而我们的mime类型,也成功的自动判断了(不然类型不对就无法成功显示内容)
动态资源处理
-
动态的内容处理也是大同小异
- 我们动态的请求类型就不止GET一种的,有POST,也许还有PUT等,根据具体情况自己加判断。然后动态的内容一般是一些接口,而我们接口的内容可能放在api文件夹下,那就跟判断static文件夹一样判断一下。然后处理动态资源的逻辑,看要返回什么内容回去给用户和设置什么响应头信息
// 处理动态资源
if ((method === 'GET' || method === 'POST') && url.startsWith('/api')) {
// ...处理动态资源的逻辑
}
常见的mime类型展示
- 文本文件:
- text/plain:纯文本文件
- text/html:HTML 文件
- text/css:CSS 样式表文件
- text/javascript:JavaScript 文件
- application/json:JSON 数据
- 图像文件:
- image/jpeg:JPEG 图像
- image/png:PNG 图像
- image/gif:GIF 图像
- image/svg+xml:SVG 图像
- 音频文件:
- audio/mpeg:MPEG 音频
- audio/wav:WAV 音频
- audio/midi:MIDI 音频
- 视频文件:
- video/mp4:MP4 视频
- video/mpeg:MPEG 视频
- video/quicktime:QuickTime 视频
- 应用程序文件:
- application/pdf:PDF 文件
- application/zip:ZIP 压缩文件
- application/x-www-form-urlencoded:表单提交数据
- multipart/form-data:多部分表单数据
转载自:https://juejin.cn/post/7361409349733744681