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一样的格式后,成功。

--

GO语言 GOLANG 上传微信电子小票图片的更多相关文章

  1. C语言 HTTP上传文件-利用libcurl库上传文件

    原文  http://justwinit.cn/post/7626/ 通常情况下,一般很少使用C语言来直接上传文件,但是遇到使用C语言编程实现文件上传时,该怎么做呢? 借助开源的libcurl库,我们 ...

  2. Slog71_选取、上传和显示本地图片GET !(微信小程序之云开发-全栈时代3)

    ArthurSlog SLog-71 Year·1 Guangzhou·China Sep 12th 2018 ArthurSlog Page GitHub NPM Package Page 掘金主页 ...

  3. 从web编辑器 UEditor 中单独提取图片上传,包含多图片单图片上传以及在线涂鸦功能

    UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码.(抄的...) UEditor是非常好用的富文 ...

  4. hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images

    hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images, 本例子主要是使用HTML5 的File API,建立一個可存取到该file的url, 一个空的img标签,ID为img0,把 ...

  5. 【转】asp.net(c#)使用HttpWebRequest附加携带请求参数以post方式模拟上传大文件(以图片为例)到Web服务器端

    原文地址:http://docode.top/Article/Detail/10002 目录: 1.Http协议上传文件(以图片为例)请求报文体内容格式 2.完整版HttpWebRequest模拟上传 ...

  6. php用jquery-ajax上传多张图片限制图片大小

    php用jquery-ajax上传多张图片限制图片大小 /** * 上传图片,默认大小限制为3M * @param String $fileInputName * @param number $siz ...

  7. MVC下form表单一次上传多种类型的图片(每种类型的图片可以上传多张)

    form表单一次上传多种类型的图片(每种类型的图片可以上传多张) controller中的action方法 public ActionResult UploadImage( )        { in ...

  8. springboot上传文件并检查图片大小与格式

    @PostMapping(value = "/uploadDriverImage") public JsonResVo uploadDriverImage(@RequestPara ...

  9. vue代码上传服务器后背景图片404解决方法

    问题:代码上传服务器后,图片404,使用的font-awesome图标也是404 解决办法: 如果你用了vue-cil,那么在build目录下找到utils.js中的ExtractTextPlugin ...

  10. iOS 使用AFN 进行单图和多图上传 摄像头/相册获取图片,压缩图片

    图片上传时必要将图片进行压缩,不然会上传失败 首先是同系统相册选择图片和视频.iOS系统自带有UIImagePickerController,可以选择或拍摄图片视频,但是最大的问题是只支持单选,由于项 ...

随机推荐

  1. 力扣574(MySQL)-当选者(中等)

    题目: 表: Candidate 表: Vote id 是自动递增的主键,CandidateId 是 Candidate 表中的 id. 问题:请编写 sql 语句来找到当选者的名字,上面的例子将返回 ...

  2. 力扣535(java)-TinyURL的加密与解密(中等)

    题目: TinyURL 是一种 URL 简化服务, 比如:当你输入一个 URL https://leetcode.com/problems/design-tinyurl 时,它将返回一个简化的URL  ...

  3. 3 种发布策略,解决 K8s 中快速交付应用的难题

    作者 | 郝树伟(流生)阿里云高级研发工程师 前言 软件技术更新换代很快,但我们追求的目标是一直不变的,那就是在安全稳定的前提下,增加应用的部署频率,缩短产品功能的迭代周期,这样的好处就是企业可以在更 ...

  4. 解决方案|致拓T8数字化ERP

    ​简介:通过快速构建敏捷ERP系统,实现从销售到财务的全流程闭环管理,助力企业数字化升级. 「致拓T8数字化ERP」解决方案聚焦业财一体,助力企业卓有成效地提升经营收益,赋能企业个性化数字生产管理.本 ...

  5. 基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台

    简介: 本文将对 RocketMQ-Exporter 的设计实现做一个简单的介绍,读者可通过本文了解到 RocketMQ-Exporter 的实现过程,以及通过 RocketMQ-Exporter 来 ...

  6. dotnet 6 在 win7 系统 AES CFB 抛出不支持异常

    本文记录在 win7 系统上调用 AES 加密时,采用 CFB 模式,可能抛出 CryptographicException 异常 可以看到抛出的异常提示是 System.Security.Crypt ...

  7. WPF 修复 ContextMenu 在开启 PerMonitorV2 后所用 DPI 错误

    本文告诉大家如何修复 WPF 的 ContextMenu 在开启 PerMonitorV2 之后,在双屏不同的 DPI 的设备上,在副屏弹出的 ContextMenu 使用了主屏的 DPI 导致缩放错 ...

  8. 支持 dotnet 6 的 dnSpy 神器版本

    官方的 dnSpy 在 2021 时,由于某些吃瓜的原因 wtfsck 将 dnSpy 给 Archived 掉,在大佬被哄好之前,预计是不再更新.最新官方版本对 dotnet 6 的支持较弱,对于很 ...

  9. dotnet 修复在 Linux 上使用 SkiaSharp 提示找不到 libSkiaSharp 库

    本文告诉大家如何简单修复在 Linux 上使用 SkiaSharp 提示找不到 libSkiaSharp 库 我的应用在 Windows 上跑的好好的,放在 Linux 上一运行就炸掉了,异常内容如下 ...

  10. C++多态与虚拟:Objects 实例化(Objects Instantiation)探究

    一.Objects的创建 依据已有的class CPoint ,我们可以产生一个或多个object(对象),或者说是产生一个instance(实体): CPoint aPoint(7.2); // a ...