静态文件(如图片)的访问地址与实际存储的地址一般是不一样的。
例如在blog-service中文件的访问地址为/static/...但是实际的文件存储地址为/storage/uploads目录下。
那么gin是如何做到两个地址间的映射的?

我们做了什么

我们只需要在路由中注册StaticFS,告诉gin框架我们要将/static/storage/uploads目录关联起来

  1. func NewRouter() *gin.Engine {
  2. ...
  3. r.POST("/upload/file", upload.UploadFile)
  4. r.StaticFS("/static", http.Dir(global.AppSetting.UploadSavePath))
  5. apiv1 := r.Group("/api/v1"){...}
  6. return r
  7. }

gin做了什么

  • 查看StaticFS方法

    1. func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
    2. if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
    3. panic("URL parameters can not be used when serving a static folder")
    4. }
    5. handler := group.createStaticHandler(relativePath, fs)
    6. urlPattern := path.Join(relativePath, "/*filepath")
    7. group.GET(urlPattern, handler)
    8. group.HEAD(urlPattern, handler)
    9. return group.returnObj()
    10. }

    1.暴露的地址中禁止使用*:
    2.创建一个gin.HandlerFunc并注册到路由

  • 查看创建gin.HandlerFunc的方法为createStaticHandler

    1. func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
    2. absolutePath := group.calculateAbsolutePath(relativePath)
    3. fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
    4. return func(c *Context) {
    5. if _, noListing := fs.(*onlyFilesFS); noListing {
    6. c.Writer.WriteHeader(http.StatusNotFound)
    7. }
    8. file := c.Param("filepath")
    9. // Check if file exists and/or if we have permission to access it
    10. f, err := fs.Open(file)
    11. if err != nil {
    12. c.Writer.WriteHeader(http.StatusNotFound)
    13. c.handlers = group.engine.noRoute
    14. // Reset index
    15. c.index = -1
    16. return
    17. }
    18. f.Close()
    19. fileServer.ServeHTTP(c.Writer, c.Request)
    20. }
    21. }

1.http.StripPrefix返回了一个http.HandlerFunc类型的函数(即一个Handler)
2.将http包下的http.HandlerFunc转换成了gin.HandlerFunc

总结:
http.StripPrefix创建了Handler

  • 移除URL前缀,
  • 调用http.FileServer(fs)的ServeHttp

封装为gin.HandlerFunc
在StaticFS方法里进行注册