第30章:实战项目三 —— 文件分享服务
本章目标
使用 Gin 构建一个支持文件上传、分享链接、过期控制的文件分享服务
核心功能
go
// 模型
type SharedFile struct {
gorm.Model
Filename string `json:"filename"`
FilePath string `json:"-"`
FileSize int64 `json:"file_size"`
ShareCode string `gorm:"uniqueIndex" json:"share_code"` // 6位分享码
Password string `json:"-"`
ExpireAt time.Time `json:"expire_at"`
DownloadCnt int `gorm:"default:0" json:"download_count"`
UserID uint `json:"user_id"`
}
// 上传文件
func Upload(c *gin.Context) {
file, _ := c.FormFile("file")
password := c.PostForm("password")
expireHours, _ := strconv.Atoi(c.DefaultPostForm("expire_hours", "24"))
// 保存文件
dst := "./uploads/" + uuid.New().String() + "_" + file.Filename
c.SaveUploadedFile(file, dst)
// 创建分享记录
share := SharedFile{
Filename: file.Filename,
FilePath: dst,
FileSize: file.Size,
ShareCode: generateShareCode(),
Password: password,
ExpireAt: time.Now().Add(time.Duration(expireHours) * time.Hour),
UserID: c.GetUint("user_id"),
}
db.Create(&share)
c.JSON(201, gin.H{"share_code": share.ShareCode, "expire_at": share.ExpireAt})
}
// 下载文件(验证密码和过期时间)
func Download(c *gin.Context) {
code := c.Param("code")
password := c.Query("password")
var share SharedFile
if db.Where("share_code = ?", code).First(&share).Error != nil {
c.JSON(404, gin.H{"error": "分享码无效"})
return
}
if time.Now().After(share.ExpireAt) {
c.JSON(410, gin.H{"error": "链接已过期"})
return
}
if share.Password != "" && share.Password != password {
c.JSON(403, gin.H{"error": "密码错误"})
return
}
db.Model(&share).UpdateColumn("download_count", gorm.Expr("download_count + 1"))
c.FileAttachment(share.FilePath, share.Filename)
}API 接口
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/files/upload | 上传文件 |
| GET | /api/files | 我的文件列表 |
| GET | /api/files/:code | 文件信息 |
| GET | /dl/:code | 下载(分享链接) |
| DELETE | /api/files/:code | 删除 |
限流配置
go
// 分享下载限流:每个 IP 每分钟最多 10 次
dlGroup := r.Group("/dl")
dlGroup.Use(RateLimiter(10, time.Minute))
{
dlGroup.GET("/:code", Download)
}练习题
- 实现完整的文件分享服务。
- 添加文件类型过滤(只允许图片/PDF)。
- 实现下载次数统计和排行榜。
- 添加文件预览功能(图片在线预览,其他文件显示信息)。