hertz icon indicating copy to clipboard operation
hertz copied to clipboard

hertz add fs documentation

Open xu756 opened this issue 2 years ago • 5 comments

在golang的1.16版本增加了embed的标签,方便我们将静态资源文件打包为二进制文件。


package main

import (
    _ "embed"
    "fmt"
)

//go:embed index.html
var index string

func main() {
    fmt.Printf("测试文件内容: %s\n", index)
}

例如

//go:embed static/imgs
static/imgs下面所有的文件

//go:embed static/imgs/1.png
static/imgs下面的1.png文件

//go:embed static/imgs/*.jpg
static/imgs下面的所有的jpg文件

//go:embed static/imgs/a?.png
static/imgs下面的a1.png/a2.png

下面是hertz 示例(我的打包文件在 dist文件夹下)

文件路径

...
├── router
│   ├── router.go
├── dist
│   ├── 210.async.js
│   ├── 25.async.js
│   ├── 333.async.js
│   ├── 548.async.js
│   ├── 65.async.js
│   ├── 910.async.js
│   ├── favicon.ico
│   ├── index.html
│   ├── p__Home__index.async.js
│   ├── p__Login__index.async.js
│   ├── p__Teacher__edit.async.js
│   ├── p__Teacher__index.async.js
│   ├── t__plugin-layout__Layout.async.js
│   ├── t__plugin-layout__Layout.chunk.css
│   ├── umi.css
│   └── umi.js
├── go.main
├── go.mod
├── go.sum
...

main.go

package main

import (
	"embed"
	"server/router"
)


//go:embed dist
var Dist embed.FS

func main() {

	router.InitRouter(Dist)
}

路由文件 router.go

package router

import (
	"context"
	"embed"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/app/server"
	"server/internal/result"
	"server/internal/xerr"
	"strings"
)

func InitRouter(file embed.FS) {
	h := server.Default()
	h.StaticFS("/", &app.FS{
		Root:               "dist",                 // 根目录
		IndexNames:         []string{"index.html"}, // 索引文件
		GenerateIndexPages: true,                   // 生成索引页面
		Compress:           false,                  // 压缩
		AcceptByteRange:    false,                  // 接受字节范围
		PathRewrite:        nil,                    // 路径重写
		PathNotFound: func(ctx context.Context, c *app.RequestContext) {
			path := string(c.Path())
			// 这个函数是路径找不到绘执行这个,例如 /login /home
			// css js 文件会在 Root 文件 里面找
			// 下面匹配路径
			switch {
			case strings.HasSuffix(path, ".js"):
				return
			case strings.HasSuffix(path, ".css"):
				return
			default:
				// 必须有这一步 react vue 项目 不是 '/'路径 刷新后找不到 报 404
				// 上面匹配 js css 可以不要,样式文件 会在 Root 文件 里面找,找不到会执行上面的函数
				data, err := file.ReadFile("dist/index.html") // 读取react vue 项目的 index.html
				if err != nil {
					result.HttpError(c, xerr.ErrMsg(xerr.FIleNotExist))
					return
				}
				c.Data(200, "text/html; charset=utf-8", data)

			}
		}, // 路径未找到
		CacheDuration:        0,  // 缓存持续时间
		CompressedFileSuffix: "", // 压缩文件后缀
	})
	h.Spin()
}

PathNotFound 必须配置到项目打包文件 index.html 否则报下面错错误 image

下面可以去掉,忽略

case strings.HasSuffix(path, ".js"):
    return
case strings.HasSuffix(path, ".css"):
    return

登录页面仍然会打印下面语句 2023/11/09 12:23:02.469640 fs.go:856: [Error] HERTZ: Cannot open file="dist/login", error=open dist/login: no such file or directory 我测试了几遍,可以忽略,不知道各位大佬有没有更好的解决方法。

xu756 avatar Nov 09 '23 04:11 xu756

same to https://github.com/cloudwego/hertz/issues/630

li-jin-gou avatar Nov 09 '23 04:11 li-jin-gou

@xu756 其实你的问题不是怎么使用 fs, 你其实应该像我维护过的这个项目的这样的用法来实现你的目的 https://github.com/polarismesh/polaris-console/blob/main/router/router.go

@Skyenought 我有点看不懂你的意思,不知道你想表达什么,我在飞书群里问这个问题,然后解决了。有大佬让我提issue分享出来,我才提了这个issue。 的确,我写的这个有些需要完善。我看不懂你发个gin代码是什么意思,我提这个issue方便以后其他用户遇到这个问题可以找到,我也是在百度找了,再看源码,最终才问群的大佬,得到这个结果。gin实现这个功能,网上资源很多,非常简单。 hertz刚起步,很多功能我非常喜欢(对比gin),我刚才看了,hertz文档关于StaticFS的内容有点少。但hertz是一个非常好的框架,作为一个全栈,我现在单体已经开始从gin转到hertz,微服务也在看kitex源码。

xu756 avatar Nov 09 '23 06:11 xu756

@xu756 我重新打开了这个 issue,用来跟进 StaticFS 文档的添加。

li-jin-gou avatar Nov 09 '23 06:11 li-jin-gou

这是一个需要前后端配合的场景,刷新404,在 umi 文档也有几种解决方案,需要从前端配置,( 到配合 nginx 的解决形式,最后切换 nginx 的解决方案 ) 到 hertz 配合 embed 实现

括号内容可跳过。

rogerogers avatar Nov 09 '23 06:11 rogerogers

you can do this image image

RogueCultivators avatar Mar 09 '24 06:03 RogueCultivators

fs 的功能长期并没有很好维护,后续准备下掉。 建议参考 http.Handler adaptor, 直接使用 net/http 相关实现,可以兼容 embed.FS

xiaost avatar May 23 '25 07:05 xiaost