Compare commits
2 Commits
master
...
d952ddd4ea
| Author | SHA1 | Date | |
|---|---|---|---|
| d952ddd4ea | |||
| e761ff5be5 |
@@ -32,8 +32,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
_ "carrotskin/docs" // Swagger docs
|
||||
// _ "carrotskin/docs" // Swagger docs
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -131,7 +131,11 @@ type SecurityConfig struct {
|
||||
// Load 加载配置 - 完全从环境变量加载,不依赖YAML文件
|
||||
func Load() (*Config, error) {
|
||||
// 加载.env文件(如果存在)
|
||||
_ = godotenv.Load(".env")
|
||||
if err := godotenv.Load(".env"); err != nil {
|
||||
fmt.Printf("[Config] 注意: 未加载 .env 文件 (原因: %v)\n", err)
|
||||
} else {
|
||||
fmt.Println("[Config] 成功加载 .env 文件")
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
setDefaults()
|
||||
@@ -152,6 +156,20 @@ func Load() (*Config, error) {
|
||||
// 从环境变量中覆盖配置
|
||||
overrideFromEnv(&config)
|
||||
|
||||
// 打印关键配置加载状态
|
||||
fmt.Println("==================================================")
|
||||
fmt.Println(" CarrotSkin Configuration Check ")
|
||||
fmt.Println("==================================================")
|
||||
fmt.Printf("Server Port: %s\n", config.Server.Port)
|
||||
fmt.Printf("Database Host: %s\n", config.Database.Host)
|
||||
fmt.Printf("Redis Host: %s\n", config.Redis.Host)
|
||||
fmt.Printf("Environment: %s\n", config.Environment)
|
||||
|
||||
if config.Database.Host == "localhost" && os.Getenv("DATABASE_HOST") != "" && os.Getenv("DATABASE_HOST") != "localhost" {
|
||||
fmt.Printf("[Warning] Database Host is 'localhost' but env DATABASE_HOST is set to '%s'. Viper binding might have failed.\n", os.Getenv("DATABASE_HOST"))
|
||||
}
|
||||
fmt.Println("==================================================")
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -79,57 +79,6 @@ func (s *StorageClient) GetBucket(name string) (string, error) {
|
||||
return bucket, nil
|
||||
}
|
||||
|
||||
// GeneratePresignedURL 生成预签名上传URL (PUT方法)
|
||||
func (s *StorageClient) GeneratePresignedURL(ctx context.Context, bucketName, objectName string, expires time.Duration) (string, error) {
|
||||
url, err := s.client.PresignedPutObject(ctx, bucketName, objectName, expires)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("生成预签名URL失败: %w", err)
|
||||
}
|
||||
return url.String(), nil
|
||||
}
|
||||
|
||||
// PresignedPostPolicyResult 预签名POST策略结果
|
||||
type PresignedPostPolicyResult struct {
|
||||
PostURL string // POST的URL
|
||||
FormData map[string]string // 表单数据
|
||||
FileURL string // 文件的最终访问URL
|
||||
}
|
||||
|
||||
// GeneratePresignedPostURL 生成预签名POST URL (支持表单上传)
|
||||
// 注意:使用时必须确保file字段是表单的最后一个字段
|
||||
func (s *StorageClient) GeneratePresignedPostURL(ctx context.Context, bucketName, objectName string, minSize, maxSize int64, expires time.Duration) (*PresignedPostPolicyResult, error) {
|
||||
// 创建上传策略
|
||||
policy := minio.NewPostPolicy()
|
||||
|
||||
// 设置策略的基本信息
|
||||
policy.SetBucket(bucketName)
|
||||
policy.SetKey(objectName)
|
||||
policy.SetExpires(time.Now().UTC().Add(expires))
|
||||
|
||||
// 设置文件大小限制
|
||||
if err := policy.SetContentLengthRange(minSize, maxSize); err != nil {
|
||||
return nil, fmt.Errorf("设置文件大小限制失败: %w", err)
|
||||
}
|
||||
|
||||
// 使用MinIO客户端和策略生成预签名的POST URL和表单数据
|
||||
postURL, formData, err := s.client.PresignedPostPolicy(ctx, policy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("生成预签名POST URL失败: %w", err)
|
||||
}
|
||||
|
||||
// 移除form_data中多余的bucket字段(MinIO Go SDK可能会添加这个字段,但会导致签名错误)
|
||||
// 注意:在Go中直接delete不存在的key是安全的
|
||||
delete(formData, "bucket")
|
||||
|
||||
// 使用配置的公开访问URL构造文件的永久访问URL
|
||||
fileURL := s.BuildFileURL(bucketName, objectName)
|
||||
|
||||
return &PresignedPostPolicyResult{
|
||||
PostURL: postURL.String(),
|
||||
FormData: formData,
|
||||
FileURL: fileURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BuildFileURL 构建文件的公开访问URL
|
||||
func (s *StorageClient) BuildFileURL(bucketName, objectName string) string {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
// "context"
|
||||
"testing"
|
||||
"time"
|
||||
// "time"
|
||||
|
||||
"carrotskin/pkg/config"
|
||||
|
||||
@@ -42,30 +42,3 @@ func TestNewStorage_SkipConnectWhenNoCreds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPresignedHelpers_WithNilClient(t *testing.T) {
|
||||
s := &StorageClient{
|
||||
client: (*minio.Client)(nil),
|
||||
buckets: map[string]string{"textures": "tex-bkt"},
|
||||
publicURL: "http://localhost:9000",
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
// 预期会panic(nil client),用recover捕获
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatalf("GeneratePresignedURL expected panic with nil client")
|
||||
}
|
||||
}()
|
||||
_, _ = s.GeneratePresignedURL(ctx, "tex-bkt", "obj", time.Minute)
|
||||
}()
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatalf("GeneratePresignedPostURL expected panic with nil client")
|
||||
}
|
||||
}()
|
||||
_, _ = s.GeneratePresignedPostURL(ctx, "tex-bkt", "obj", 0, 10, time.Minute)
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user