Files
bl/common/contrib/files/img/cdn58.go

140 lines
4.4 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 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)
// 设置RefererPHP中的$referer
req.Header.Set("Referer", baiduReferer)
// 设置CookiePHP中的$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)
}