runliuv

runliuv@cnblogs

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  709 随笔 :: 0 文章 :: 127 评论 :: 98万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

GO语言 GOLANG 上传微信电子小票图片、GO HTTP POST 图片文件、GO 上传图片文件、multipart/form-data、image/jpeg、image/png。

 

GO 环境:

go version go1.21.4 windows/amd64

 

为了方便调试,我把http header Authorization、报文 meta json、都放在了TXT里。

复制代码
package test

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    person "main/models"
    "net/http"
    "os"
    "path/filepath"
    "strings"
)

func TestWxXpUp() {

    fmt.Println(" 微信电子小票上传接口 ")

    // 设置代理
    // os.Setenv("HTTP_PROXY", "http://127.0.0.1:8899")
    // os.Setenv("HTTPS_PROXY", "https://127.0.0.1:9743")

    // 获取当前工作目录
    dir, err := os.Getwd()
    if err != nil {
        fmt.Println("无法获取当前工作目录:", err)
        return
    }

    boundary := "ASSDFWDFBFWEFWWDF" //可以自己设定,需要比较复杂的字符串作
    // 图片文件 START
    picFilePath := "D:\\GO语言源码\\L1\\微信截图_20231124093553.jpg"

    var picBytes []byte
    if _, err := os.Lstat(picFilePath); err == nil {
        file, _ := os.Open(picFilePath)
        defer file.Close()

        picBytes, _ = io.ReadAll(file)
    } else {
        log.Fatal("文件不存在:" + picFilePath)
    }

    // 图片文件 END

    bodyFilePath := filepath.Join(dir, "xp_body.txt")
    headerAuthPath := filepath.Join(dir, "xp_header.txt")

    // 报文 meta json
    bodyBytes, err := os.ReadFile(bodyFilePath)
    if err != nil {
        fmt.Println("无法读取文件:", err)
        return
    }

    strBodyMeta := string(bodyBytes)
    fmt.Println("文件内容:" + strBodyMeta)

    // http header Authorization
    headerBytes, err := os.ReadFile(headerAuthPath)
    if err != nil {
        fmt.Println("无法读取文件:", err)
        return
    }

    strHeader := string(headerBytes)
    fmt.Println("文件内容:" + strHeader)

    fileContentType := "image/jpeg"
    pngsuffix := ".png"
    //用文件后缀判定图片类型,不一定准确
    picFilePathLowered := strings.ToLower(picFilePath)
    if endsWith(picFilePathLowered, pngsuffix) {
        fileContentType = "image/png"
    }

    // HTTP 拼装开始
    picData := "--" + boundary + "\r\n"
    // HTTP 文本组装
    picData = picData + "Content-Disposition:form-data;name=\"meta\"\r\nContent-Type:application/json\r\n\r\n"
    picData = picData + string(bodyBytes) + "\r\n"
    picData = picData + "--" + boundary + "\r\n"
    // HTTP 文件组装
    picData = picData + "Content-Disposition: form-data; name=\"file\"; filename=\"" + picFilePath + "\"\r\n" + "Content-Type: " + fileContentType + "\r\n\r\n"
    picData = picData + string(picBytes) + "\r\n"
    //最后的boundary 尾部会加2个-
    picData = picData + "--" + boundary + "--"

    var myUrl = "https://api.mch.weixin.qq.com/v3/marketing/shopping-receipt/shoppingreceipts"

    // 创建一个HTTP请求,并设置请求方法和URL
    req, err := http.NewRequest("POST", myUrl, strings.NewReader(picData))
    if err != nil {
        fmt.Println("创建请求时发生错误:", err)
        return
    }

    // 设置请求的Content-Type头部为
    req.Header.Set("Content-Type", "multipart/form-data;boundary="+boundary)
    req.Header.Set("Authorization", strHeader)
    // 设置Accept 和 User-Agent 不然也会报错
    req.Header.Set("User-Agent", "MyCustomUserAgent")
    req.Header.Set("Accept", "application/json")

    // 创建一个HTTP客户端并发送请求
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("发送请求时发生错误:", err)
        return
    }
    defer resp.Body.Close()

    // 读取响应的内容
    body := &bytes.Buffer{}
    _, err = body.ReadFrom(resp.Body)
    if err != nil {
        fmt.Println("读取响应时发生错误:", err)
        return
    }

    // 打印响应的状态码和内容
    fmt.Println("响应状态码:", resp.StatusCode)
    fmt.Println("响应内容:", body.String())
}

func endsWith(str, suffix string) bool {
    return len(str) >= len(suffix) && str[len(str)-len(suffix):] == suffix
}
复制代码

 

控制台输出:

微信电子小票上传接口 
文件body内容:{"transaction_id":"4200001992202311246726XXXX","openid":"ooIeqs39EYwsHoRh_q0GmQE_XXXX","sha256":"7a205561ba1995dac8f41851dd256731393a64db7435f75befa876c4dd3dc5c5","transaction_sub_mchid":"40082XXXX"}
文件header auth内容:WECHATPAY2-SHA256-RSA2048 mchid="21220XXXX",nonce_str="e804ba603e06410b9a04ffe5575fe385",signature="U+uBfn3xQIWmonvjvloWIupNPduKpfOut3y6YqETM7WjKxO6eCjn+pRPbT642XTiWeK7gEMsGF0V4n1ttgpd50870zUSepqbuU6jJ8TFwzE5cUQTvKs+7LJTy72XooS4wx8X+mAgwyR6nnhlRbdNAeQE+2TDVhs98juhvlGrxeuaNBavtHs/Hvp8kVcjsi/FXtNmU7ugMIS7EpSxgnF7qCf3x9MtTyzI1hvsq7oIjFcK3TY3+qDRQpcxYkiDXrB/eJmVipHbNAj+nfwMqlK3dUi0kftTIEnLkT36NKNuI+7B/Wy5hiv8dfrZZYkNVo9HYkvjO+rQRuj3QDgtlJROCQ==",timestamp="1700813854",serial_no="7B3505BC4F006C713E217C2E3FCE6ED5xxxxx"
响应状态码: 401
响应内容: {"code":"SIGN_ERROR","message":"Http头Authorization中的timestamp与发起请求的时间不得超过5分钟"}

 

重点:

picData = picData + "Content-Disposition: form-data; name=\"file\"; filename=\"" + picFilePath + "\"\r\n" + "Content-Type: " + fileContentType + "\r\n\r\n"

这段原生报文里,一个空格都不能多,一个引号都不能少。否则微信会报错。

先前用C#调试,老报错,尝试POSTMAN,居然是通的,把“https://api.mch.weixin.qq.com”改成 HTTP的,然后用FIDDLER 抓包。和C#程序生成的报文做对比,才发现少了些空格,把它改成POSTMAN一样的格式后,成功。

--

 

posted on   runliuv  阅读(133)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示