130 lines
3.5 KiB
Go
130 lines
3.5 KiB
Go
// 上传文件到cloudflare R2
|
||
package handler
|
||
import (
|
||
"bytes"
|
||
"fmt"
|
||
"net/http"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/aws/aws-sdk-go/aws"
|
||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||
"github.com/aws/aws-sdk-go/aws/session"
|
||
"github.com/aws/aws-sdk-go/service/s3"
|
||
)
|
||
|
||
type UploadHandler struct {
|
||
accessKey string
|
||
secretKey string
|
||
bucket string
|
||
endpoint string
|
||
customDomain string
|
||
}
|
||
|
||
type UploadRequest struct {
|
||
File string `json:"file" binding:"required"`
|
||
APIKey string `json:"apikey" binding:"required"`
|
||
}
|
||
|
||
type UploadResponse struct {
|
||
ImageURL string `json:"image_url"`
|
||
Success bool `json:"success"`
|
||
}
|
||
|
||
func NewUploadHandler(accessKey, secretKey, bucket, endpoint, customDomain string) *UploadHandler {
|
||
return &UploadHandler{
|
||
accessKey: accessKey,
|
||
secretKey: secretKey,
|
||
bucket: bucket,
|
||
endpoint: endpoint,
|
||
customDomain: customDomain,
|
||
}
|
||
}
|
||
// 上传文件到cloudflare R2。判断文件是否是图片,如果是图片,则上传到R2,并返回图片的url,如果不是图片,则返回错误。
|
||
// 图片大小限制为10M,图片格式为jpg, jpeg, png, gif, bmp, tiff, webp
|
||
// HandleUpload 上传文件到Cloudflare R2
|
||
func (h *UploadHandler) HandleUpload(c *gin.Context) {
|
||
// 解析请求体
|
||
file, header, err := c.Request.FormFile("file")
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to read file from request"})
|
||
return
|
||
}
|
||
defer file.Close()
|
||
|
||
// 读取文件内容
|
||
fileBuffer := make([]byte, header.Size)
|
||
_, err = file.Read(fileBuffer)
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read file content"})
|
||
return
|
||
}
|
||
|
||
// 验证文件类型
|
||
contentType := http.DetectContentType(fileBuffer)
|
||
if !isImage(contentType) {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid file type. Only images are allowed"})
|
||
return
|
||
}
|
||
|
||
// 验证文件大小
|
||
if header.Size > 10<<20 { // 10MB
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "File size exceeds the limit of 10MB"})
|
||
return
|
||
}
|
||
|
||
// 上传文件到R2
|
||
imageURL, err := h.uploadToR2(fileBuffer, header.Filename, contentType)
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to upload file to R2: %v", err)})
|
||
return
|
||
}
|
||
|
||
// 返回结果
|
||
response := UploadResponse{
|
||
ImageURL: imageURL,
|
||
Success: true,
|
||
}
|
||
c.JSON(http.StatusOK, response)
|
||
}
|
||
|
||
// uploadToR2 上传文件到Cloudflare R2
|
||
func (h *UploadHandler) uploadToR2(file []byte, fileName, contentType string) (string, error) {
|
||
// 创建S3会话
|
||
sess, err := session.NewSession(&aws.Config{
|
||
Endpoint: aws.String(h.endpoint),
|
||
Region: aws.String("auto"),
|
||
Credentials: credentials.NewStaticCredentials(h.accessKey, h.secretKey, ""),
|
||
})
|
||
if err != nil {
|
||
return "", fmt.Errorf("failed to create S3 session: %v", err)
|
||
}
|
||
|
||
// 创建S3服务客户端
|
||
svc := s3.New(sess)
|
||
|
||
// 上传文件到R2
|
||
_, err = svc.PutObject(&s3.PutObjectInput{
|
||
Bucket: aws.String(h.bucket),
|
||
Key: aws.String(fileName),
|
||
Body: bytes.NewReader(file),
|
||
ContentType: aws.String(contentType),
|
||
ACL: aws.String("public-read"), // 设置文件为公开可读
|
||
})
|
||
if err != nil {
|
||
return "", fmt.Errorf("failed to upload file to R2: %v", err)
|
||
}
|
||
|
||
// 生成文件的URL
|
||
imageURL := fmt.Sprintf("https://%s/%s", h.customDomain, fileName)
|
||
return imageURL, nil
|
||
}
|
||
|
||
// isImage 检查文件是否是图片
|
||
func isImage(contentType string) bool {
|
||
allowedTypes := []string{"image/jpeg", "image/png", "image/gif", "image/bmp", "image/tiff", "image/webp"}
|
||
for _, t := range allowedTypes {
|
||
if contentType == t {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
} |