GO语言 GOLANG 上传微信电子小票图片
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 上传微信电子小票图片的更多相关文章
- C语言 HTTP上传文件-利用libcurl库上传文件
原文 http://justwinit.cn/post/7626/ 通常情况下,一般很少使用C语言来直接上传文件,但是遇到使用C语言编程实现文件上传时,该怎么做呢? 借助开源的libcurl库,我们 ...
- Slog71_选取、上传和显示本地图片GET !(微信小程序之云开发-全栈时代3)
ArthurSlog SLog-71 Year·1 Guangzhou·China Sep 12th 2018 ArthurSlog Page GitHub NPM Package Page 掘金主页 ...
- 从web编辑器 UEditor 中单独提取图片上传,包含多图片单图片上传以及在线涂鸦功能
UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码.(抄的...) UEditor是非常好用的富文 ...
- hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images, 本例子主要是使用HTML5 的File API,建立一個可存取到该file的url, 一个空的img标签,ID为img0,把 ...
- 【转】asp.net(c#)使用HttpWebRequest附加携带请求参数以post方式模拟上传大文件(以图片为例)到Web服务器端
原文地址:http://docode.top/Article/Detail/10002 目录: 1.Http协议上传文件(以图片为例)请求报文体内容格式 2.完整版HttpWebRequest模拟上传 ...
- php用jquery-ajax上传多张图片限制图片大小
php用jquery-ajax上传多张图片限制图片大小 /** * 上传图片,默认大小限制为3M * @param String $fileInputName * @param number $siz ...
- MVC下form表单一次上传多种类型的图片(每种类型的图片可以上传多张)
form表单一次上传多种类型的图片(每种类型的图片可以上传多张) controller中的action方法 public ActionResult UploadImage( ) { in ...
- springboot上传文件并检查图片大小与格式
@PostMapping(value = "/uploadDriverImage") public JsonResVo uploadDriverImage(@RequestPara ...
- vue代码上传服务器后背景图片404解决方法
问题:代码上传服务器后,图片404,使用的font-awesome图标也是404 解决办法: 如果你用了vue-cil,那么在build目录下找到utils.js中的ExtractTextPlugin ...
- iOS 使用AFN 进行单图和多图上传 摄像头/相册获取图片,压缩图片
图片上传时必要将图片进行压缩,不然会上传失败 首先是同系统相册选择图片和视频.iOS系统自带有UIImagePickerController,可以选择或拍摄图片视频,但是最大的问题是只支持单选,由于项 ...
随机推荐
- 力扣184(MySQL)-部门工资最高的员工(中等)
题目: 表: Employee 表: Department 编写SQL查询以查找每个部门中薪资最高的员工.按 任意顺序 返回结果表.查询结果格式如下例所示. 解题思路: 方法一:窗口函数和多表联结 ...
- 牛客网-SQL专项训练17
①SQL查询中使用WHere子句指出的是:查询条件 ②Mysql中表student_table(id,name,birth,sex),查询重复姓名.重复次数,并按重复次数降序排列,正确的是(A)? 解 ...
- Docker Volume 的经常用法区别
对于使用 NFS 的 Docker 数据卷,配置示例应当类似于这样: version: '3' services: my_service: image: your_image volumes: # 挂 ...
- Raft 共识算法1-Raft基础
Raft 共识算法1-Raft基础 Raft算法中译版地址:http://www.redisant.cn/etcd/contact 英原论文地址:https://raft.github.io/raft ...
- net core下链路追踪skywalking安装和简单使用
当我们用很多服务时,各个服务间的调用关系是怎么样的?各个服务单调用的顺序\时间性能怎么样?服务出错了,到底是哪个服务引起的?这些问题我们用什么方案解决呢,以前的方式是各个系统自己单独做日志,出了问题从 ...
- python 操作xls
目录 写入文件 demo01 demo02 写入文件 demo01 # 读取:xlrd # 写入:xlwt # 修改(追加写入):xlutils import xlrd import xlwt fro ...
- rpc 和 http的区别
- blocks (单调栈)
题目描述 解析 对于这道题,他要求大于k的数进行操作,所以直接让每个数减k,然后用前缀和维护一下与0比较就可以了,因为一段区间和的平 均值大于k的话,那么这就是一个合法区间,即为操作后的这个区间和大于 ...
- 从XML配置角度理解Spring AOP
本文分享自华为云社区<Spring高手之路18--从XML配置角度理解Spring AOP>,作者: 砖业洋__. 1. Spring AOP与动态代理 1.1 Spring AOP和动态 ...
- 降本提效 | AIRIOT设备运维管理解决方案
传统运维多是使用在本地化系统,以人工运维和独立系统执行运维工作,重点关注的是设施运行,存在以下几个问题: 1.信息孤岛:本地化系统的接口不同,功能单一独立,各个系统之间的数据无法对接.交互,形 ...