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) }