140 lines
4.4 KiB
Go
140 lines
4.4 KiB
Go
package baidu
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"mime/multipart"
|
||
"net/http"
|
||
"os"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// 百度图床全局配置
|
||
const (
|
||
// 上传接口地址
|
||
baiduUploadURL = "https://wenku.baidu.com/user/api/editorimg"
|
||
// 必需的Referer
|
||
baiduReferer = "https://wenku.baidu.com/"
|
||
// 固定Cookie(可根据实际情况替换)
|
||
baiduCookie = "BDUSS=3plTHA0aHpRNGI3MmIxTkpmNVpWTTYtLXpVWjlaRjdRQzFsNmxQNlNufkRiWGhvSVFBQUFBJCQAAAAAAAAAAAEAAAB5WXC40tfDzsTPs8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMPgUGjD4FBoS"
|
||
// 请求超时时间
|
||
baiduTimeout = 30 * time.Second
|
||
)
|
||
|
||
// BaiduUploadResponse 百度图床接口返回JSON结构
|
||
type BaiduUploadResponse struct {
|
||
Link string `json:"link"` // 图片链接字段
|
||
}
|
||
|
||
// BaiduImgUpload 百度图床上传函数,对齐PHP功能
|
||
// filepath: 本地文件路径
|
||
// filename: 上传时的文件名(对应PHP的setPostFilename)
|
||
// 返回值: 处理后的图片URL,错误信息
|
||
func BaiduImgUpload(filepath string, filename string) (string, error) {
|
||
// 1. 参数校验
|
||
if filepath == "" {
|
||
return "", fmt.Errorf("本地文件路径不能为空")
|
||
}
|
||
if filename == "" {
|
||
return "", fmt.Errorf("上传文件名不能为空")
|
||
}
|
||
|
||
// 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 添加文件字段(对应PHP的'file'字段,设置上传文件名)
|
||
fileWriter, err := bodyWriter.CreateFormFile("file", filename)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建文件表单字段失败: %w", err)
|
||
}
|
||
// 复制文件内容到请求体
|
||
if _, err := io.Copy(fileWriter, file); err != nil {
|
||
return "", fmt.Errorf("复制文件内容到请求体失败: %w", err)
|
||
}
|
||
|
||
// 4. 创建HTTP POST请求
|
||
contentType := bodyWriter.FormDataContentType()
|
||
req, err := http.NewRequest(http.MethodPost, baiduUploadURL, bodyBuf)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建HTTP请求失败: %w", err)
|
||
}
|
||
|
||
// 5. 设置请求头(对齐PHP的请求头配置)
|
||
setBaiduRequestHeaders(req, contentType)
|
||
|
||
// 6. 发送HTTP请求
|
||
client := &http.Client{Timeout: baiduTimeout}
|
||
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 baiduResp BaiduUploadResponse
|
||
if err := json.Unmarshal(respBody, &baiduResp); err != nil {
|
||
return "", fmt.Errorf("解析JSON响应失败: %w, 响应内容: %s", err, string(respBody))
|
||
}
|
||
|
||
// 9. 校验响应结果(对应PHP的isset($arr['link']))
|
||
if baiduResp.Link == "" {
|
||
return "", fmt.Errorf("上传失败!接口错误,响应内容: %s", string(respBody))
|
||
}
|
||
|
||
// 10. 替换域名(对应PHP的str_replace操作)
|
||
imgURL := strings.Replace(baiduResp.Link, ".cdn.bcebos.com", ".bj.bcebos.com", 1)
|
||
|
||
return imgURL, nil
|
||
}
|
||
|
||
// setBaiduRequestHeaders 设置百度图床必需的请求头
|
||
func setBaiduRequestHeaders(req *http.Request, contentType string) {
|
||
// 设置Content-Type(包含multipart boundary)
|
||
req.Header.Set("Content-Type", contentType)
|
||
// 设置Referer(PHP中的$referer)
|
||
req.Header.Set("Referer", baiduReferer)
|
||
// 设置Cookie(PHP中的$cookie)
|
||
req.Header.Set("Cookie", baiduCookie)
|
||
// 补充必要的请求头,提升兼容性
|
||
req.Header.Set("Connection", "keep-alive")
|
||
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("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"
|
||
// 上传时的文件名(可自定义,对应PHP的setPostFilename)
|
||
uploadFilename := "custom-test.jpg"
|
||
|
||
// 调用百度图床上传函数
|
||
imgURL, err := BaiduImgUpload(localFilePath, uploadFilename)
|
||
if err != nil {
|
||
fmt.Printf("百度图床上传失败: %v\n", err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("百度图床上传成功,图片URL: %s\n", imgURL)
|
||
}
|