nuxt3使用记录五:启动压缩构建并自定义静态资源代理(不仅限于nuxt3)

我们构建项目时,为了节约带宽资源,加速网页的加载,一个有效的配置是启用压缩,现在浏览器通常支持三种压缩格式:Accept-Encoding:gzip, deflate, br
nuxt3也同样自带压缩功能,默认支持两种格式gzip,br

// nuxt.config.ts
    nitro: {
        compressPublicAssets: true,        // 启动压缩
    }

然后构建完的静态资源会同时存在三种格式:1. 源文件 2.源文件被压缩成gzip格式 3.源文件被压缩成br格式

对比可以发现,压缩后大小减少很多,其中br格式压缩率最高

nuxt3通过SSG构建完静态资源,它会提醒你直接执行命令npx serve .output/public即可代理运行,并且会根据请求头判断客户端是否支持压缩格式,支持的话优先返回压缩后的文件。不得不说nuxt3在细节方面还是做得不错的。

第一种代理方式

一般情况下,传统的vue3项目,构建完网上的资料大多介绍使用nginx进行代理,确实是很成熟的方案,包括启用了压缩资源的代理方式,网上很多资料,我也没采用这种方式,就不说了,nuxt3构建的自然也可以使用nginx来进行代理

第二种代理方式

服务器安装好node环境,然后使用npx serve .output/public 一键代理,并且也支持指定端口,这个也不难,我就不细说了

PS:这种代理优先返回gzip格式,而不是压缩率更高的br格式,并且没找到设置的方法

第三种代理方式

重点当然是实现自定义代理,如果不考虑压缩格式,其实众多后端框架都已经自带静态资源的代理能力,也很容易实现。

然而,需要代理具有压缩格式的静态资源的自定义代理实现,网上居然找不到现成的方案,于是我就自己摸索了一下,发现也不难实现,以下是我使用golang-gin框架实现的自定义代理。

PS:静态资源代理的本质就是返回对应的文件,成熟的http框架都带有返回文件的接口

核心就是判断请求头是否支持压缩格式,支持的话,就返回对应压缩格式的文件,不支持的话就返回源文件,而返回文件就是用框架自带的File()接口,一个成熟的http框架肯定有该接口的,和我们后端返回文件的是同一个接口

  1. 首先处理未明确指定文件的请求,如根目录的请求,这种请求都指向对应的index.html,所以手工指定成index.html即可
  2. 判断文件类型,设置"Content-Type"请求头,这一步得根据源文件的格式来手工设置
  3. 判断请求的文件是否存在,不存在返回404.html(非必要)
  4. 依次判断是否存在br,gzip等压缩格式的文件,如果有,则返回压缩后的文件,否则返回源文件
func ProxyStatic(c *gin.Context) {
	var file string
	urlPath := c.Request.URL.Path
	// 路径以/结尾,或者直接以一个目录结尾的,默认其请求的是index.html
	if strings.HasSuffix(urlPath, "/") || !strings.Contains(urlPath, ".") {
		file = path.Join("./web", urlPath, "index.html")
		c.Header("Content-Type", `text/html; charset=utf-8`) // 因为后续可能返回它的压缩文件,必须得手工设置类型,否则c.File获取的是压缩文件的类型
	} else { // 其他则是带具体文件名的请求,当前我的文件类型里只有.js和.css,如果还有其他,需在此补充
		file = path.Join("./web", urlPath)
		if strings.HasSuffix(urlPath, ".js") {
			c.Header("Content-Type", `application/javascript; charset=utf-8`) // 因为后续可能返回它的压缩文件,必须得手工设置类型,否则c.File获取的是压缩文件的类型
		} else if strings.HasSuffix(urlPath, ".css") {
			c.Header("Content-Type", `text/css; charset=utf-8`) // 因为后续可能返回它的压缩文件,必须得手工设置类型,否则c.File获取的是压缩文件的类型
		}
	}
	// 判断文件是否存在,如果不存在则返回404.html
	if !fileExists(file) {
		file = path.Join("./web", "404.html")
	}
	// 下面是判断请求是否支持压缩,如果支持,先判断是否有对应的压缩文件,有则返回压缩文件,无则返回原文件
	acceptEncoding := c.Request.Header.Get("Accept-Encoding")
	if strings.Contains(acceptEncoding, "br") && fileExists(file+".br") {
		c.Header("Content-Encoding", "br") // 告诉客户端,返回的压缩文件是br格式
		c.File(file + ".br")
	} else if strings.Contains(acceptEncoding, "gzip") && fileExists(file+".gz") {
		c.Header("Content-Encoding", "gzip") // 告诉客户端,返回的压缩文件是gzip格式
		c.File(file + ".gz")
	} else {
		c.File(file)
	}
}

代码也很简单,根据自己实际情况略作修改即可,终点是要根据源文件的类型,手动设置"Content-Type",不能等c.File(file)自动设置,因为它返回压缩文件时识别的类型是压缩格式,不是源文件的,会导致前端解析失败

路由就如下方式设置:

	// 这些资源没对应压缩格式,直接使用自带的静态资源接口就可以
	router.StaticFile("/", "./web")
	router.Static("/images/", "./web/images")

	// 自定义静态资源代理
	router.GET("/dist/*name", app.ProxyStatic)

这样我整个项目都可以使用自己的代理程序,更自由了。服务器也不需要安装node,golang的性能还是强过node的,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lsjweiyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值