前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >(5) 静态前端网站容器化 - 为什么不用 Nginx 而自建 HTTP Server?

(5) 静态前端网站容器化 - 为什么不用 Nginx 而自建 HTTP Server?

作者头像
老麦
发布2025-02-12 15:04:24
发布2025-02-12 15:04:24
5700
代码可运行
举报
文章被收录于专栏:Go与云原生Go与云原生
运行总次数:0
代码可运行

(5) 静态前端网站容器化 - 为什么不用 Nginx 而自建 HTTP Server?

建议点击 查看原文 查看最新内容。

原文链接: https://typonotes.com/posts/2025/02/09/static-sap-dockerize-customize-httpserve/

众所周知, 我们在容器化 静态网站 的时候为了实现 一次编译, 处处运行 的目标, 在 index.html 中插入了一个变量 __CONFIG__, 在启动的时候进行替换为正式后端的地址。 可以参考

  1. (2) Vue3 / React 静态网站项目容器化 - 实战案例[1]
  2. (3) 静态前端网站容器化 - 容器篇[2]

为什么要自建?还是不是被逼的!!然后在实践中经常会遇到各种条件的约束。 公司平台团队以安全为由,锁定了 K8s Pod 文件系统策略, 将目录限制为只读状态。 虽然可以使用 mount 目录方式绕过, 但是我懒啊, 不想因为不同平台再定制不同的管理策略。

对于这种情况, 我使用 gin-gonic/gin 自定义一个 HTTP Server, 使用 https://github.com/spf13/afero 创建了一个内存文件系统, 将所有静态资源全部复制 内存空间 中, 这样就随便我修改了。

除此之外还有一个好处: 自定服务器还有一个好处是可以通过 环境变量 更方便的管理各种功能, 比花实践折腾配置模版(nginx) 体验更好。

Demo 项目可以参考: https://github.com/tangx/httpstatic

重点来了

在 gin 中提供了 StaticFS, 但参数要求是 http.FileSystem 接口

代码语言:javascript
代码运行次数:0
复制
func (group *gin.RouterGroup) StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes

于是使用了 http.FS()fs.FS 接口进行封装。

代码语言:javascript
代码运行次数:0
复制
// 定义
// func http.FS(fsys fs.FS) http.FileSystem

// 使用
r.StaticFS("/", http.FS(fsys))

但是, 使用 spf13/afero 创建的内存系统的默认返回接口是 afreo.Fs

代码语言:javascript
代码运行次数:0
复制
// func afero.NewMemMapFs() afero.Fs

m := afero.NewMemMapFs()

解决方法

解决方法很简单, 自定一个 结构体 mfswrapper 实现 fs.FS 接口即可。

代码语言:javascript
代码运行次数:0
复制
// mfswrapper wraps afero.Fs to implement fs.FS.
// cause gin.StaticFS() requires fs.FS.
// but afero.Fs does not implement fs.FS.
type mfswrapper struct {
 afero.Fs
}

func (w mfswrapper) Open(name string) (fs.File, error) {
 return w.Fs.Open(name)
}

部分代码如下

  1. 创建内存文件系统 m
  2. copywalk() 将本地文件复制到内存文件系统 m 中。
  3. 读取 index.html 并使用 inject() 函数替换 __CONFIG__ 为真实变量。
代码语言:javascript
代码运行次数:0
复制
// mfsMode serves files from the memory directory.
// if k8s restrict modifying files in the container.
func mfsMode(dist string) fs.FS {
 m := afero.NewMemMapFs()

 err := copywalk(dist, m, dist)
if err != nil {
panic(err)
 }

// replace index.html content.
 index := filepath.Join(dist, "index.html")
if data, replaced := inject(index); replaced {
if err := afero.WriteFile(m, "index.html", data, 0644); err != nil {
   panic(err)
  }
 }

 mw := &mfswrapper{m}

return mw
}

为什么要这样

这样就绕过了 只读文件系统 的要求。 更重要的是, 无论以后应用部署到其他任何容器平台, 都不用再为其管理专门的 部署配置

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 熊猫云原生Go 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • (5) 静态前端网站容器化 - 为什么不用 Nginx 而自建 HTTP Server?
    • 重点来了
    • 解决方法
    • 为什么要这样
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档