| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | package storage | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"context" | 
					
						
							|  |  |  |  | 	"crypto/hmac" | 
					
						
							|  |  |  |  | 	"crypto/sha1" | 
					
						
							|  |  |  |  | 	"encoding/base64" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							|  |  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2025-08-02 02:54:21 +08:00
										 |  |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	"path/filepath" | 
					
						
							|  |  |  |  | 	"strings" | 
					
						
							|  |  |  |  | 	"time" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	"github.com/qiniu/go-sdk/v7/auth/qbox" | 
					
						
							|  |  |  |  | 	"github.com/qiniu/go-sdk/v7/storage" | 
					
						
							|  |  |  |  | 	"go.uber.org/zap" | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	sharedStorage "tyapi-server/internal/shared/storage" | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // QiNiuStorageService 七牛云存储服务 | 
					
						
							|  |  |  |  | type QiNiuStorageService struct { | 
					
						
							|  |  |  |  | 	accessKey     string | 
					
						
							|  |  |  |  | 	secretKey     string | 
					
						
							|  |  |  |  | 	bucket        string | 
					
						
							|  |  |  |  | 	domain        string | 
					
						
							|  |  |  |  | 	logger        *zap.Logger | 
					
						
							|  |  |  |  | 	mac           *qbox.Mac | 
					
						
							|  |  |  |  | 	bucketManager *storage.BucketManager | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // QiNiuStorageConfig 七牛云存储配置 | 
					
						
							|  |  |  |  | type QiNiuStorageConfig struct { | 
					
						
							|  |  |  |  | 	AccessKey string `yaml:"access_key"` | 
					
						
							|  |  |  |  | 	SecretKey string `yaml:"secret_key"` | 
					
						
							|  |  |  |  | 	Bucket    string `yaml:"bucket"` | 
					
						
							|  |  |  |  | 	Domain    string `yaml:"domain"` | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // NewQiNiuStorageService 创建七牛云存储服务 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | func NewQiNiuStorageService(accessKey, secretKey, bucket, domain string, logger *zap.Logger) *QiNiuStorageService { | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	mac := qbox.NewMac(accessKey, secretKey) | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 	// 使用默认配置,不需要指定region | 
					
						
							|  |  |  |  | 	cfg := storage.Config{} | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	bucketManager := storage.NewBucketManager(mac, &cfg) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return &QiNiuStorageService{ | 
					
						
							|  |  |  |  | 		accessKey:     accessKey, | 
					
						
							|  |  |  |  | 		secretKey:     secretKey, | 
					
						
							|  |  |  |  | 		bucket:        bucket, | 
					
						
							|  |  |  |  | 		domain:        domain, | 
					
						
							|  |  |  |  | 		logger:        logger, | 
					
						
							|  |  |  |  | 		mac:           mac, | 
					
						
							|  |  |  |  | 		bucketManager: bucketManager, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // UploadFile 上传文件到七牛云 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | func (s *QiNiuStorageService) UploadFile(ctx context.Context, fileBytes []byte, fileName string) (*sharedStorage.UploadResult, error) { | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	s.logger.Info("开始上传文件到七牛云", | 
					
						
							|  |  |  |  | 		zap.String("file_name", fileName), | 
					
						
							|  |  |  |  | 		zap.Int("file_size", len(fileBytes)), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 生成唯一的文件key | 
					
						
							|  |  |  |  | 	key := s.generateFileKey(fileName) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建上传凭证 | 
					
						
							|  |  |  |  | 	putPolicy := storage.PutPolicy{ | 
					
						
							|  |  |  |  | 		Scope: s.bucket, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	upToken := putPolicy.UploadToken(s.mac) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 配置上传参数 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 	cfg := storage.Config{} | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	formUploader := storage.NewFormUploader(&cfg) | 
					
						
							|  |  |  |  | 	ret := storage.PutRet{} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 上传文件 | 
					
						
							|  |  |  |  | 	err := formUploader.Put(ctx, &ret, upToken, key, strings.NewReader(string(fileBytes)), int64(len(fileBytes)), &storage.PutExtra{}) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("文件上传失败", | 
					
						
							|  |  |  |  | 			zap.String("file_name", fileName), | 
					
						
							|  |  |  |  | 			zap.String("key", key), | 
					
						
							|  |  |  |  | 			zap.Error(err), | 
					
						
							|  |  |  |  | 		) | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("文件上传失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 构建文件URL | 
					
						
							|  |  |  |  | 	fileURL := s.GetFileURL(ctx, key) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	s.logger.Info("文件上传成功", | 
					
						
							|  |  |  |  | 		zap.String("file_name", fileName), | 
					
						
							|  |  |  |  | 		zap.String("key", key), | 
					
						
							|  |  |  |  | 		zap.String("url", fileURL), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 	return &sharedStorage.UploadResult{ | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 		Key:      key, | 
					
						
							|  |  |  |  | 		URL:      fileURL, | 
					
						
							|  |  |  |  | 		MimeType: s.getMimeType(fileName), | 
					
						
							|  |  |  |  | 		Size:     int64(len(fileBytes)), | 
					
						
							|  |  |  |  | 		Hash:     ret.Hash, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GenerateUploadToken 生成上传凭证 | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) GenerateUploadToken(ctx context.Context, key string) (string, error) { | 
					
						
							|  |  |  |  | 	putPolicy := storage.PutPolicy{ | 
					
						
							|  |  |  |  | 		Scope: s.bucket, | 
					
						
							|  |  |  |  | 		// 设置过期时间(1小时) | 
					
						
							|  |  |  |  | 		Expires: uint64(time.Now().Add(time.Hour).Unix()), | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	token := putPolicy.UploadToken(s.mac) | 
					
						
							|  |  |  |  | 	return token, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetFileURL 获取文件访问URL | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) GetFileURL(ctx context.Context, key string) string { | 
					
						
							|  |  |  |  | 	// 如果是私有空间,需要生成带签名的URL | 
					
						
							|  |  |  |  | 	if s.isPrivateBucket() { | 
					
						
							|  |  |  |  | 		deadline := time.Now().Add(time.Hour).Unix() // 1小时过期 | 
					
						
							|  |  |  |  | 		privateAccessURL := storage.MakePrivateURL(s.mac, s.domain, key, deadline) | 
					
						
							|  |  |  |  | 		return privateAccessURL | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 公开空间直接返回URL | 
					
						
							|  |  |  |  | 	return fmt.Sprintf("%s/%s", s.domain, key) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetPrivateFileURL 获取私有文件访问URL | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) GetPrivateFileURL(ctx context.Context, key string, expires int64) (string, error) { | 
					
						
							|  |  |  |  | 	baseURL := s.GetFileURL(ctx, key) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// TODO: 实际集成七牛云SDK生成私有URL | 
					
						
							|  |  |  |  | 	s.logger.Info("生成七牛云私有文件URL", | 
					
						
							|  |  |  |  | 		zap.String("key", key), | 
					
						
							|  |  |  |  | 		zap.Int64("expires", expires), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 模拟返回私有URL | 
					
						
							|  |  |  |  | 	return fmt.Sprintf("%s?token=mock_private_token&expires=%d", baseURL, expires), nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // DeleteFile 删除文件 | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) DeleteFile(ctx context.Context, key string) error { | 
					
						
							|  |  |  |  | 	s.logger.Info("删除七牛云文件", zap.String("key", key)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	err := s.bucketManager.Delete(s.bucket, key) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("删除文件失败", | 
					
						
							|  |  |  |  | 			zap.String("key", key), | 
					
						
							|  |  |  |  | 			zap.Error(err), | 
					
						
							|  |  |  |  | 		) | 
					
						
							|  |  |  |  | 		return fmt.Errorf("删除文件失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	s.logger.Info("文件删除成功", zap.String("key", key)) | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // FileExists 检查文件是否存在 | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) FileExists(ctx context.Context, key string) (bool, error) { | 
					
						
							|  |  |  |  | 	// TODO: 实际集成七牛云SDK检查文件存在性 | 
					
						
							|  |  |  |  | 	s.logger.Info("检查七牛云文件存在性", zap.String("key", key)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 模拟文件存在 | 
					
						
							|  |  |  |  | 	return true, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetFileInfo 获取文件信息 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | func (s *QiNiuStorageService) GetFileInfo(ctx context.Context, key string) (*sharedStorage.FileInfo, error) { | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	fileInfo, err := s.bucketManager.Stat(s.bucket, key) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("获取文件信息失败", | 
					
						
							|  |  |  |  | 			zap.String("key", key), | 
					
						
							|  |  |  |  | 			zap.Error(err), | 
					
						
							|  |  |  |  | 		) | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("获取文件信息失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 	return &sharedStorage.FileInfo{ | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 		Key:      key, | 
					
						
							|  |  |  |  | 		Size:     fileInfo.Fsize, | 
					
						
							|  |  |  |  | 		MimeType: fileInfo.MimeType, | 
					
						
							|  |  |  |  | 		Hash:     fileInfo.Hash, | 
					
						
							|  |  |  |  | 		PutTime:  fileInfo.PutTime, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ListFiles 列出文件 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | func (s *QiNiuStorageService) ListFiles(ctx context.Context, prefix string, limit int) ([]*sharedStorage.FileInfo, error) { | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	entries, _, _, hasMore, err := s.bucketManager.ListFiles(s.bucket, prefix, "", "", limit) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("列出文件失败", | 
					
						
							|  |  |  |  | 			zap.String("prefix", prefix), | 
					
						
							|  |  |  |  | 			zap.Error(err), | 
					
						
							|  |  |  |  | 		) | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("列出文件失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 	var fileInfos []*sharedStorage.FileInfo | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	for _, entry := range entries { | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 		fileInfo := &sharedStorage.FileInfo{ | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 			Key:      entry.Key, | 
					
						
							|  |  |  |  | 			Size:     entry.Fsize, | 
					
						
							|  |  |  |  | 			MimeType: entry.MimeType, | 
					
						
							|  |  |  |  | 			Hash:     entry.Hash, | 
					
						
							|  |  |  |  | 			PutTime:  entry.PutTime, | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		fileInfos = append(fileInfos, fileInfo) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	_ = hasMore // 暂时忽略hasMore | 
					
						
							|  |  |  |  | 	return fileInfos, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // generateFileKey 生成文件key | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) generateFileKey(fileName string) string { | 
					
						
							|  |  |  |  | 	// 生成时间戳 | 
					
						
							|  |  |  |  | 	timestamp := time.Now().Format("20060102_150405") | 
					
						
							|  |  |  |  | 	// 生成随机字符串 | 
					
						
							|  |  |  |  | 	randomStr := fmt.Sprintf("%d", time.Now().UnixNano()%1000000) | 
					
						
							|  |  |  |  | 	// 获取文件扩展名 | 
					
						
							|  |  |  |  | 	ext := filepath.Ext(fileName) | 
					
						
							|  |  |  |  | 	// 构建key: 日期/时间戳_随机数.扩展名 | 
					
						
							|  |  |  |  | 	key := fmt.Sprintf("certification/%s/%s_%s%s", | 
					
						
							|  |  |  |  | 		time.Now().Format("20060102"), timestamp, randomStr, ext) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return key | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // getMimeType 根据文件名获取MIME类型 | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) getMimeType(fileName string) string { | 
					
						
							|  |  |  |  | 	ext := strings.ToLower(filepath.Ext(fileName)) | 
					
						
							|  |  |  |  | 	switch ext { | 
					
						
							|  |  |  |  | 	case ".jpg", ".jpeg": | 
					
						
							|  |  |  |  | 		return "image/jpeg" | 
					
						
							|  |  |  |  | 	case ".png": | 
					
						
							|  |  |  |  | 		return "image/png" | 
					
						
							|  |  |  |  | 	case ".pdf": | 
					
						
							|  |  |  |  | 		return "application/pdf" | 
					
						
							|  |  |  |  | 	case ".gif": | 
					
						
							|  |  |  |  | 		return "image/gif" | 
					
						
							|  |  |  |  | 	case ".bmp": | 
					
						
							|  |  |  |  | 		return "image/bmp" | 
					
						
							|  |  |  |  | 	case ".webp": | 
					
						
							|  |  |  |  | 		return "image/webp" | 
					
						
							|  |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		return "application/octet-stream" | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // isPrivateBucket 判断是否为私有空间 | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) isPrivateBucket() bool { | 
					
						
							|  |  |  |  | 	// 这里可以根据配置或域名特征判断 | 
					
						
							|  |  |  |  | 	// 私有空间的域名通常包含特定标识 | 
					
						
							|  |  |  |  | 	return strings.Contains(s.domain, "private") || | 
					
						
							|  |  |  |  | 		strings.Contains(s.domain, "auth") || | 
					
						
							|  |  |  |  | 		strings.Contains(s.domain, "secure") | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // generateSignature 生成签名(用于私有空间访问) | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) generateSignature(data string) string { | 
					
						
							|  |  |  |  | 	h := hmac.New(sha1.New, []byte(s.secretKey)) | 
					
						
							|  |  |  |  | 	h.Write([]byte(data)) | 
					
						
							|  |  |  |  | 	return base64.URLEncoding.EncodeToString(h.Sum(nil)) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // UploadFromReader 从Reader上传文件 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | func (s *QiNiuStorageService) UploadFromReader(ctx context.Context, reader io.Reader, fileName string, fileSize int64) (*sharedStorage.UploadResult, error) { | 
					
						
							|  |  |  |  | 	// 读取文件内容 | 
					
						
							|  |  |  |  | 	fileBytes, err := io.ReadAll(reader) | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 		return nil, fmt.Errorf("读取文件失败: %w", err) | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-13 16:36:20 +08:00
										 |  |  |  | 	return s.UploadFile(ctx, fileBytes, fileName) | 
					
						
							| 
									
										
										
										
											2025-07-11 21:05:58 +08:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-08-02 02:54:21 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // DownloadFile 从七牛云下载文件 | 
					
						
							|  |  |  |  | func (s *QiNiuStorageService) DownloadFile(ctx context.Context, fileURL string) ([]byte, error) { | 
					
						
							|  |  |  |  | 	s.logger.Info("开始从七牛云下载文件", zap.String("file_url", fileURL)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建HTTP客户端 | 
					
						
							|  |  |  |  | 	client := &http.Client{ | 
					
						
							|  |  |  |  | 		Timeout: 30 * time.Second, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建请求 | 
					
						
							|  |  |  |  | 	req, err := http.NewRequestWithContext(ctx, "GET", fileURL, nil) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("创建请求失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 发送请求 | 
					
						
							|  |  |  |  | 	resp, err := client.Do(req) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("下载文件失败", | 
					
						
							|  |  |  |  | 			zap.String("file_url", fileURL), | 
					
						
							|  |  |  |  | 			zap.Error(err), | 
					
						
							|  |  |  |  | 		) | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("下载文件失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 检查响应状态 | 
					
						
							|  |  |  |  | 	if resp.StatusCode != http.StatusOK { | 
					
						
							|  |  |  |  | 		s.logger.Error("下载文件失败,状态码异常", | 
					
						
							|  |  |  |  | 			zap.String("file_url", fileURL), | 
					
						
							|  |  |  |  | 			zap.Int("status_code", resp.StatusCode), | 
					
						
							|  |  |  |  | 		) | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("下载文件失败,状态码: %d", resp.StatusCode) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 读取文件内容 | 
					
						
							|  |  |  |  | 	fileContent, err := io.ReadAll(resp.Body) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		s.logger.Error("读取文件内容失败", | 
					
						
							|  |  |  |  | 			zap.String("file_url", fileURL), | 
					
						
							|  |  |  |  | 			zap.Error(err), | 
					
						
							|  |  |  |  | 		) | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("读取文件内容失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	s.logger.Info("文件下载成功", | 
					
						
							|  |  |  |  | 		zap.String("file_url", fileURL), | 
					
						
							|  |  |  |  | 		zap.Int("file_size", len(fileContent)), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return fileContent, nil | 
					
						
							|  |  |  |  | } |