接口说明
- 适用对象:服务商/电商平台
- 请求URL:https://api.mch.weixin.qq.com/v3/merchant/media/upload
- 逻辑流程:
- 从云储存或小程序端获取图片二进制数据
- 使用crypto生成文件摘要
- 使用crypto生成签名和授权信息(需要先有文件名和文件摘要)
- 自定义分割字符串boundary和HTTP头Content-Type
- 创建传输body的头部和尾部,并与文件拼接
- 发送请求
1. 获取图片二进制数据
可以从云储存获取,或小程序端传参
小程序获取的是ArrayBuffer,在后续使用中需要转型成Buffer
场景1: 从云储存获取图片buffer
- 云函数代码
// [云储存文件id] 可以从小程序端传入
const fileRes = await cloud.downloadFile({fileID: '云储存文件id'})
const imgBuffer = fileRes.fileContent
场景2:从小程序端获取图片buffer
- 小程序代码
const fileSystemManager = wx.getFileSystemManager()
const buffer = fileSystemManager.readFileSync('图片路径')
wx.cloud.callFunction({
name: '云函数名称',
data: {
buffer,
filename: '图片名.jpg'
}
})
- 云函数代码
let { buffer, filename } = event
const imgBuffer = Buffer.from(buffer)
2. 生成摘要、创建meta
const hash = crypto.createHash('sha256');
hash.update(imgBuffer);
let sha256 = hash.digest('hex')
let meta = { filename, sha256 }
3. 生成签名、创建授权信息
let getAuthorization = async function(meta) {
// 获取商户私钥、证书序列号、商户号
// (可以储存在云数据中,从云数据库获取)
const priKey = '商户私钥'
const serialNo = '商户证书序列号'
const mchid= '商户号'
// 生成随机序列
let nonceStr = Math.random().toString()
// 获取当前时间戳(这里需要的是秒数不是毫秒,要除以1000)
let timestamp = Math.floor(Date.now() / 1000)
// 创建待签名文本
let signatureText = "POST\n"
+ "/v3/merchant/media/upload\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ JSON.stringify(meta)+"\n"
// 生成签名
let sign = crypto.createSign('RSA-SHA256')
sign.update(signatureText)
let signature = sign.sign(priKey, 'base64')
// 合成授权信息
let authorization = 'WECHATPAY2-SHA256-RSA2048'
+ ` mchid="${mchid}"`
+ `,nonce_str="${nonceStr}"`
+ `,timestamp="${timestamp}"`
+ `,serial_no="${serialNo}"`
+ `,signature="${signature}"`
return authorization
}
4. 自定义分割字符串boundary和HTTP头Content-Type
// 自定义分割字符串(可以自行定义,和发送的内容不重复即可)
let boundary = 'miwoo-boundary-' + Math.random()
let contentType = 'multipart/form-data; boundary=' + boundary
5. 创建传输body的前半部分和尾部,并与文件拼接
// 创建body的前半部分并转换为buffer
// 注意反引号`与单引号'的区别
// 分割符要在boundary前加--
let beginBuffer = Buffer.from(
`--${boundary}\r\n`
+ 'Content-Disposition: form-data; name="meta";\r\n'
+ 'Content-Type: application/json\r\n'
+ '\r\n'
+ `${JSON.stringify(meta)}\r\n`
+ `--${boundary}\r\n`
+ `Content-Disposition: form-data; name="file"; filename="${filename}";\r\n`
+ 'Content-Type: image/jpg\r\n'
+ '\r\n'
)
// 创建body尾部(第一个\r\n是接在imgBuffer后面的换行)
// 结束分割符要在boundary两边加--
let endBuffer = Buffer.from(`\r\n--${boundary}--\r\n`)
// 将imgBuffer加入头部与尾部,拼接成完整body(不能直接使用+号连接)
let body = Buffer.concat([beginBuffer,imgBuffer,endBuffer])
6. 发送请求
axios({
method: 'POST',
url: 'https://api.mch.weixin.qq.com/v3/merchant/media/upload',
headers: {
'Authorization': authorization,
'Content-Type': contentType
},
data: body
})
.then(res => {
console.log(res.data)
})
完整流程
const cloud = require('wx-server-sdk')
cloud.init()
const crypto = require('crypto') //使用crypto生成文件摘要以及签名
const axios = require('axios') //使用axios发送请求(npm install axios)
exports.main =async (event, context) => {
// 1. 获取图片buffer
const imgBuffer = '从云储存或小程序获取'
// 获取文件名(请自行获取)
const filename = '图片名.jpg'
// 2. 生成文件摘要
const hash = crypto.createHash('sha256');
hash.update(imgBuffer);
let sha256 = hash.digest('hex')
let meta = { filename, sha256 }
// 3. 获取签名(使用上面的签名函数)
let authorization = await getAuthorization(meta)
// 4. 自定义分割字符串和Content-Type
let boundary = 'miwoo-boundary-' + Math.random()
let contentType = 'multipart/form-data; boundary=' + boundary
// 5. 创建(拼接)body
let beginBuffer = Buffer.from(
`--${boundary}\r\n`
+ 'Content-Disposition: form-data; name="meta";\r\n'
+ 'Content-Type: application/json\r\n'
+ '\r\n'
+ `${JSON.stringify(meta)}\r\n`
+ `--${boundary}\r\n`
+ `Content-Disposition: form-data; name="file"; filename="${filename}";\r\n`
+ 'Content-Type: image/jpg\r\n'
+ '\r\n'
)
let endBuffer = Buffer.from(`\r\n--${boundary}--\r\n`)
let body = Buffer.concat([beginBuffer,imgBuffer,endBuffer])
// 6. 发送请求
return await axios({
method: 'POST',
url: 'https://api.mch.weixin.qq.com/v3/merchant/media/upload',
headers: {
'Authorization': authorization,
'Content-Type': contentType
},
data: body
})
.then(res => {
console.log(res.data)
return res.data.media_id
})
}
欢迎留言
本文为**电商平台(云开发)**的填坑之作,欢迎提出不足之处、分享云开发的经验和坑。
请问下有接口实现通过media_id进行预览图片吗?
简单易懂,写的太好了