使用gin框架搭建web静态资源服务

2,881 阅读4分钟

从一个问题开始

这两天做项目遇到一个上传图片的问题,前端把图片上传给后台,后台接收图片并保存在服务器的静态资源目录并发回给前端一个文件资源路径,通过该路径可以直接访问文件资源。我这里是使用gin框架做图片上传处理的代码如下

func UploadGoodsImg(c *gin.Context) (string, error) {
    file, err := c.FormFile("f1")//获取文件
    if err != nil {
        zap.L().Error("获取文件失败", zap.Error(err))
        return "", err
    }
    fmt.Println(file.Filename)
    dst := "./img/goodsImage/" + file.Filename//文件存放路径
    err = c.SaveUploadedFile(file, dst)
    if err != nil {
        zap.L().Error("存储文件到服务器失败", zap.Error(err))
        return "", err
    }
    return dst, err
}

可以看到这里我直接把文件存放路径和文件名拼接在一起作为访问路径返回给前端,但是测试的时候发现通过返回的这个地址无法访问到文件资源。这是为什么?经过一番搜索才知道我这种直接把存储路径当作图片访问路径的方法是不可行的,如果要让外部请求本项目HTTP Server的时候可以提供静态的访问,需要在项目中设置文件服务,下面我来谈谈gin中实现文件服务的两种方法

gin.Static()

func (group *RouterGroup) Static(relativePath, root string) IRoutes {
    return group.StaticFS(relativePath, Dir(root, false))
}

源码注释对static的解释如下

static从给定的文件系统根目录提供文件。内部使用了 http.FileServer,因此使用 http.NotFound 而不是路由器的 NotFound 处理程序

主要看第一句话,从给定的文件系统根目录提供文件这句话什么意思,先说一下参数的含义:第一个参数是所访问资源的URL,第二个参数是资源存放在服务器上的路径, 访问文件资源时指定的url会被映射到服务器上真正存放静态资源的路径上,下面是我项目代码中的使用实例

r := gin.New()
r.Static("/static/", "./img/goodsImage")

这段代码可以这么理解:假设上传图片返回的文件存储地址是./img/goodsImage/4.jpg一开始测试的时候,我在浏览器的地址栏输入的是http://localhost:8080/img/goodsImage/4.jpg(不可访问),现在使用static设置了文件服务再访问该资源,输入的地址变为http://localhost:8080/static/4.jpg(可访问)。也就是说设置的相对路径/static/映射到服务器上的位置是./img/goodsImage,当然这个相对路径(访问静态资源的URL)可以随便你设置,只要能映射到服务器上存放静态资源的文件夹位置就行。

gin.StaticFS()

StaticFS 的工作方式与 Static() 类似,但可以使用自定义的 http.FileSystem 代替。 Gin 默认用户:gin.Dir()

Dir 返回一个可供 http.FileServer() 使用的 http.FileSystem。它在 router.Static() 内部使用。如果 listDirectory == true,那么它的工作方式与 http.Dir() 相同,否则它返回一个阻止 http.FileServer() 列出目录文件的文件系统。

先说用法:和gin.Static()一样,第一个参数是请求文件资源的URL,第二个参数是文件系统,可以是http.Dir()gin.Dir()

使用http.Dir()的时候用法如下:

    r.StaticFS("/static/", http.Dir("./img/goodsImage"))

含义和Static一样,访问路由也相同,不过可以显示出./img/goodImage目录下的所有文件,在浏览器里输入http://localhost:8080/static时显示页面如下

1.png

使用gin.Dir()时,第二个参数除了要输入路径之外还可以需要输入一个布尔值,来控制是否展示文件目录的内容例如

r.StaticFS("/static/", gin.Dir("./img/goodsImage",true))//表示可以显示资源目录

为true 的时候效果输入http://localhost:8080/static显示的内容和上图一样,如果改为false,也就是r.StaticFS("/static/", gin.Dir("./img/goodsImage",false))时,再访问/static/不会展示出列表,但是可以展示具体的请求资源,看下图

image-20220915142350516.png

PS:一开始我用谷歌浏览器测试r.StaticFS("/static/", gin.Dir("./img/goodsImage",true))的时候访问了/static/的目录,当我改成false之后惊讶的发现居然还能看到/static/目录下的文件,我一度怀疑我理解错了,于是我换成edage再次访问/static/这次访问不到了,这才突然意识到,原来是内容被缓存再浏览器里了。清除谷歌浏览器缓存之后,再次访问/static/果然成功了,文件列表没有被显示,大家测试的时候引以为戒。😆

剩下的两个方法

gin设置资源服务还有两个方法:

  • StaticFile注册单个路由以便为本地文件系统的单个文件提供服务
  • StaticFileFSStaticFile 一样工作,但可以使用自定义的 http.FileSystem

关于这两个方法我没有测试,大家有兴趣可以向详细了解,如果有疑问欢迎大家在评论区留言~