const cloud = require('wx-server-sdk')
const request = require('request');
const crypto = require('crypto');
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
try {
const {
access_token,
queryParams
} = event
const ctxEco = getEcoCtx('https://api.weixin.qq.com/cgi-bin/express/intracity/querystore')
console.log("ctxEco", ctxEco)
const req = queryParams
console.log("req", req)
const newReq = getNewReq(ctxEco, req)
console.log("newReq", newReq)
const ctxSign = getSignCtx('https://api.weixin.qq.com/cgi-bin/express/intracity/querystore')
console.log("ctxSign", ctxSign)
const signature = getSignature(ctxSign, newReq)
console.log("signature", signature)
const response = await queryStore(access_token, signature, newReq)
console.log("response", response)
return response;
} catch (error) {
console.error('请求错误:', error);
return error;
}
}
async function queryStore(access_token, signature, newReq) {
const url = `https://api.weixin.qq.com/cgi-bin/express/intracity/querystore?access_token=${access_token}`;
const rp = options =>
new Promise((resolve, reject) => {
request(options, (error, response, body) => {
if (error) {
reject(error);
}
resolve(response);
});
});
const result = await rp({
url: url,
method: 'POST',
json: true,
headers: {
'Wechatmp-Appid': 'appid',
'Wechatmp-TimeStamp': newReq.req_ts,
'Wechatmp-Signature': signature
},
body: newReq
});
return result.body;
}
function getSignCtx(url) {
let ctx = {
local_private_key: "-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----",
local_sn: "sn",
local_appid: "appid",
url_path: url
}
return ctx
}
function getEcoCtx(url) {
let ctx = {
local_sym_key: "sym_key",
local_sym_sn: "sym_sn",
local_appid: "appid",
url_path: url
}
return ctx
}
function getNewReq(ctx, req) {
const { local_sym_key, local_sym_sn, local_appid, url_path } = ctx
const local_ts = Math.floor(Date.now() / 1000)
const nonce = crypto.randomBytes(16).toString('base64').replace(/=/g, '')
const reqex = {
_n: nonce,
_appid: local_appid,
_timestamp: local_ts
}
const real_req = Object.assign({}, reqex, req)
const plaintext = JSON.stringify(real_req)
const aad = `${url_path}|${local_appid}|${local_ts}|${local_sym_sn}`
const real_key = Buffer.from(local_sym_key, "base64")
const real_iv = crypto.randomBytes(12)
const real_aad = Buffer.from(aad, "utf-8")
const real_plaintext = Buffer.from(plaintext, "utf-8")
const cipher = crypto.createCipheriv("aes-256-gcm", real_key, real_iv)
cipher.setAAD(real_aad)
let cipher_update = cipher.update(real_plaintext)
let cipher_final = cipher.final()
const real_ciphertext = Buffer.concat([cipher_update, cipher_final])
const real_authTag = cipher.getAuthTag()
const iv = real_iv.toString("base64")
const data = real_ciphertext.toString("base64")
const authtag = real_authTag.toString("base64")
const req_data = {
iv,
data,
authtag,
}
const new_req = {
req_ts: local_ts,
req_data: JSON.stringify(req_data)
}
return new_req
}
function getSignature(ctx, req) {
const { local_private_key, local_sn, local_appid, url_path } = ctx
const { req_ts, req_data } = req
const payload = `${url_path}\n${local_appid}\n${req_ts}\n${req_data}`
const data_buffer = Buffer.from(payload, 'utf-8')
const key_obj = {
key: local_private_key,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
}
const sig_buffer = ss_buffer = crypto.sign(
'RSA-SHA256',
data_buffer,
key_obj
)
const sig = sig_buffer.toString('base64')
return sig
}
const result = await rp({ url: url, method: 'POST', // json: true, // 自动将请求体转换为JSON格式 headers: { 'Content-type': 'application/json;charset=utf-8', 'Wechatmp-Appid': 'wx5c396ba640e68749', 'Wechatmp-TimeStamp': newReq.req_ts, 'Wechatmp-Signature': signature }, body: newReq.req_data // 将加密数据作为请求体 }); return result.body;
以上是我在云函数中使用引入request库发起的请求,对于加密和签名后的api请求要把json:true去除
还有一个问题
const new_req = { req_ts: local_ts, req_data: JSON.stringify(req_data) } return new_req
官方代码中加密后return的new_req是带时间戳的,方便签名方法直接传参使用,我们具体发送请求的时候一定要用new_req.req_data,
当上述 两个问题加在一起时 会导致 40234 , invalid signature
如果你的签名和加密参数没问题不妨看下有没有像我一样粗心 😊