Files
bl/common/contrib/files/imgdd/imgdd.go

148 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"time"
)
// 全局配置与PHP代码保持一致
const (
// imgdd上传接口地址
imgddUploadURL = "https://imgdd.com/upload"
// 必需的Referer
imgddReferer = "https://imgdd.com/"
// 请求超时时间
imgddTimeout = 30 * time.Second
)
// ImgddUploadResponse imgdd接口返回JSON结构
// 对应PHP响应中的url和message字段
type ImgddUploadResponse struct {
URL string `json:"url"` // 上传成功返回的图片URL
Message string `json:"message"` // 上传失败返回的提示信息
}
// ImgddImgUpload imgdd图床上传函数完全对齐PHP功能
// filepath: 本地文件路径
// filename: 上传时的自定义文件名对应PHP的setPostFilename
// 返回值: 图片URL错误信息
func ImgddImgUpload(filepath string, filename string) (string, error) {
// 1. 参数校验
if filepath == "" {
return "", errors.New("本地文件路径不能为空")
}
if filename == "" {
return "", errors.New("上传文件名不能为空")
}
// 2. 打开本地文件
file, err := os.Open(filepath)
if err != nil {
return "", fmt.Errorf("打开本地文件失败: %w, 路径: %s", err, filepath)
}
defer file.Close() // 延迟关闭文件,确保资源释放
// 3. 构建multipart/form-data请求体
bodyBuf := &bytes.Buffer{}
bodyWriter := multipart.NewWriter(bodyBuf)
defer bodyWriter.Close() // 延迟关闭writer确保请求体完整
// 3.1 添加文件字段(字段名"image"对应PHP的'image' => $file设置自定义上传文件名
fileWriter, err := bodyWriter.CreateFormFile("image", filename)
if err != nil {
return "", fmt.Errorf("创建文件表单字段失败: %w", err)
}
// 3.2 复制文件内容到请求体
if _, err := io.Copy(fileWriter, file); err != nil {
return "", fmt.Errorf("复制文件内容到请求体失败: %w", err)
}
// 4. 创建HTTP POST请求
contentType := bodyWriter.FormDataContentType() // 自动包含boundary无需手动拼接
req, err := http.NewRequest(http.MethodPost, imgddUploadURL, bodyBuf)
if err != nil {
return "", fmt.Errorf("创建HTTP请求失败: %w", err)
}
// 5. 设置请求头与PHP代码保持一致
setImgddRequestHeaders(req, contentType)
// 6. 发送HTTP请求
client := &http.Client{
Timeout: imgddTimeout,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, // 注意:字段名是 InsecureSkipVerify非 TLSInsecureSkipVerify
},
},
}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("发送HTTP请求失败: %w", err)
}
defer resp.Body.Close() // 延迟关闭响应体
// 7. 读取响应内容
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应内容失败: %w", err)
}
// 8. 解析JSON响应
var imgddResp ImgddUploadResponse
if err := json.Unmarshal(respBody, &imgddResp); err != nil {
return "", fmt.Errorf("解析JSON响应失败: %w, 响应内容: %s", err, string(respBody))
}
// 9. 按PHP逻辑判断响应结果
if imgddResp.URL != "" {
// 存在url字段上传成功
return imgddResp.URL, nil
} else if imgddResp.Message != "" {
// 存在message字段返回对应错误
return "", fmt.Errorf("上传失败请重试(%s", imgddResp.Message)
} else {
// 既无url也无message接口错误
return "", fmt.Errorf("上传失败!接口错误,响应内容: %s", string(respBody))
}
}
// setImgddRequestHeaders 设置imgdd必需的请求头
func setImgddRequestHeaders(req *http.Request, contentType string) {
// 设置Content-Type包含multipart boundary
req.Header.Set("Content-Type", contentType)
// 设置Referer与PHP一致接口可能做了来源校验
req.Header.Set("Referer", imgddReferer)
// 补充通用请求头,提升兼容性
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Accept", "*/*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
}
// 示例调用
func main() {
// 配置本地文件路径和上传文件名(请替换为实际值)
localFilePath := "./test.jpg" // 本地图片实际路径
uploadFilename := "custom-img.jpg" // 上传时的自定义文件名(可包含后缀)
// 调用imgdd上传函数
imgURL, err := ImgddImgUpload(localFilePath, uploadFilename)
if err != nil {
fmt.Printf("imgdd图床上传失败: %v\n", err)
return
}
fmt.Printf("imgdd图床上传成功图片URL: %s\n", imgURL)
}