生产真实 key 为 `YYYY/MM/<UnixNano>.<ext>`(无前缀、无 day 层), 与 route/question/page.go:uploadImage 一致;internal/storage 里三个 上传函数仍用旧的 `picture/ 前缀 + YYYY/MM/DD + 15hex + 无扩展名`,从未上线。 - PictureKeyPrefix 置空,统一由 uploadKey 生成 key - 扩展名跟随最终 ContentType(webp 转成功用 .webp,回退原图用原格式) - OSS 原图直传通道取原文件名扩展名 - 新增 picture_test.go 锁定 key 格式,防回归
53 lines
1.7 KiB
Go
53 lines
1.7 KiB
Go
// Copyright 2022 E99p1ant. All rights reserved.
|
||
// Use of this source code is governed by a MIT-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
package storage
|
||
|
||
import (
|
||
"fmt"
|
||
"path/filepath"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// PictureKeyPrefix 是图片对象 key 的前缀。生产环境图片以无前缀方式存于
|
||
// bucket 根下(R2 PathStyle 下 bucket 名自动作为 URL 首段),故这里置空。
|
||
const PictureKeyPrefix = ""
|
||
|
||
// uploadKey 按生产口径生成对象 key:`YYYY/MM/<UnixNano><ext>`。
|
||
// 无前缀、无 day 层,文件名用纳秒时间戳保证唯一,扩展名与最终落盘内容类型一致。
|
||
func uploadKey(ext string) string {
|
||
now := time.Now()
|
||
return fmt.Sprintf("%s%d/%02d/%d%s", PictureKeyPrefix, now.Year(), int(now.Month()), now.UnixNano(), ext)
|
||
}
|
||
|
||
// extFromContentType 由 MIME 类型推导扩展名,用于保证对象 key 的扩展名
|
||
// 与 ContentType(以及实际落盘字节)严格一致,避免出现「.jpg 实为 webp」的错配。
|
||
func extFromContentType(contentType string) string {
|
||
switch contentType {
|
||
case "image/jpeg":
|
||
return ".jpg"
|
||
case "image/png":
|
||
return ".png"
|
||
case "image/gif":
|
||
return ".gif"
|
||
case "image/webp":
|
||
return ".webp"
|
||
default:
|
||
return ""
|
||
}
|
||
}
|
||
|
||
// originalExt 取原始文件名的扩展名,统一转小写。用于转换失败回退原图时
|
||
// 保留原始扩展名(与生产口径一致)。
|
||
func originalExt(filename string) string {
|
||
return strings.ToLower(filepath.Ext(filename))
|
||
}
|
||
|
||
// MaxAvatarSize is the max avatar size which is 2MB.
|
||
const MaxAvatarSize = 2 * 1024 * 1024
|
||
|
||
// MaxBackgroundSize is the max background size which is 2MB.
|
||
const MaxBackgroundSize = 2 * 1024 * 1024
|