静态文件(如图片)的访问地址与实际存储的地址一般是不一样的。
例如在blog-service中文件的访问地址为/static/...但是实际的文件存储地址为/storage/uploads目录下。
那么gin是如何做到两个地址间的映射的?
我们做了什么
我们只需要在路由中注册StaticFS,告诉gin框架我们要将/static和/storage/uploads目录关联起来
func NewRouter() *gin.Engine {...r.POST("/upload/file", upload.UploadFile)r.StaticFS("/static", http.Dir(global.AppSetting.UploadSavePath))apiv1 := r.Group("/api/v1"){...}return r}
gin做了什么
查看StaticFS方法
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {panic("URL parameters can not be used when serving a static folder")}handler := group.createStaticHandler(relativePath, fs)urlPattern := path.Join(relativePath, "/*filepath")group.GET(urlPattern, handler)group.HEAD(urlPattern, handler)return group.returnObj()}
1.暴露的地址中禁止使用
*和:
2.创建一个gin.HandlerFunc并注册到路由查看创建gin.HandlerFunc的方法为
createStaticHandlerfunc (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {absolutePath := group.calculateAbsolutePath(relativePath)fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))return func(c *Context) {if _, noListing := fs.(*onlyFilesFS); noListing {c.Writer.WriteHeader(http.StatusNotFound)}file := c.Param("filepath")// Check if file exists and/or if we have permission to access itf, err := fs.Open(file)if err != nil {c.Writer.WriteHeader(http.StatusNotFound)c.handlers = group.engine.noRoute// Reset indexc.index = -1return}f.Close()fileServer.ServeHTTP(c.Writer, c.Request)}}
1.http.StripPrefix返回了一个http.HandlerFunc类型的函数(即一个Handler)
2.将http包下的http.HandlerFunc转换成了gin.HandlerFunc
总结:
http.StripPrefix创建了Handler
- 移除URL前缀,
- 调用http.FileServer(fs)的ServeHttp
封装为gin.HandlerFunc
在StaticFS方法里进行注册
