You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Gin实现动态子目录文件服务且不暴露目录列表

实现方案

实现思路

  • 不要使用Gin内置的Static/StaticFS方法,这类方法默认会开启目录列表浏览,不符合需求
  • 手动捕获所有/media前缀的请求,自行校验路径合法性、判断目标是否为文件,仅合法文件请求才返回内容
  • 额外增加路径穿越校验,避免恶意请求访问到rooms目录外的敏感文件

完整代码示例

package main

import (
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	// 捕获所有/media前缀的请求
	r.GET("/media/*filepath", func(c *gin.Context) {
		// 1. 处理请求路径,去掉开头的斜杠
		reqPath := strings.TrimPrefix(c.Param("filepath"), "/")

		// 2. 拼接本地文件的根目录,建议替换为实际的绝对路径
		baseDir := "./uploads/rooms"
		fullPath := filepath.Join(baseDir, reqPath)

		// 3. 路径穿越校验,防止恶意请求访问目录外的文件
		absBaseDir, err := filepath.Abs(baseDir)
		if err != nil {
			c.AbortWithStatus(http.StatusNotFound)
			return
		}
		absFullPath, err := filepath.Abs(fullPath)
		if err != nil || !strings.HasPrefix(absFullPath, absBaseDir) {
			c.AbortWithStatus(http.StatusNotFound)
			return
		}

		// 4. 校验目标是否为存在的普通文件
		fileInfo, err := os.Stat(absFullPath)
		if err != nil || fileInfo.IsDir() {
			c.AbortWithStatus(http.StatusNotFound)
			return
		}

		// 5. 校验通过,返回文件
		c.File(absFullPath)
	})

	r.Run(":8080")
}

效果验证

  • 请求http://localhost:8080/media/1/a.jpg:正常返回对应图片
  • 请求http://localhost:8080/media/1:识别为目录,返回404
  • 请求http://localhost:8080/media/../../etc/passwd:路径穿越校验不通过,返回404
  • 新增rooms/3/d.jpg后不需要修改代码,直接请求http://localhost:8080/media/3/d.jpg即可正常返回

内容的提问来源于stack exchange,提问作者Anup Kumar Panwar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 10:00:03