db.js
var mysql = require('mysql');
var dbConfig = require('./db.config');
var connection = mysql.createPool(dbConfig);
module.exports = {
wx: { // 微信
_appid: 'wx943**', // 微信小程序id
_mchid: '1637*****', // 商户id
_secret: 'b959f1520e07fa7d5e9707aa4d1f874', // 微信小程序密钥
_service_trans_id: 'DADA', // 使用达达快送,或者顺丰同城
_AES256_GCM_Sn: 'fb0f63ade7cd99a89c1358********7', // 对称秘钥编号
_AES256_GCM_Key: 'O8Qe2v0Rbo55A5NJ0s2r3X0********aF5Aoc=', // 对称秘钥明文
_RSAwithSHA256_Sn: *********969972f4f0d909e359534', // 非对称秘钥编号
_RSAwithSHA256_Key: "-----BEGIN PUBLIC KEY-----\nM******************CAQEA49YRS/qTTBg754DT+3pl\nsHjbOfygHJN2ihfQOlin5zrfupQX6fVo5f+cdwMFL9Vk/NaCpT9WnozziL4M/fJf\n4rmUn8FNsmUS+xm7wvmsJSWQxyMeHsq08axJV29oQ+OTrnfWpwQdsOXRaqQ5I+tT\nLkKZR82ApkgPSYXb+yuFBmN1I6F++DtuHesBszjDkSqLGLL6zU1sbXv3IZS6QtW+\ny6N9co/rWl152RTOjqajs0LFHDgAhtLS1pAPjUmcPDb0fGolzq9+tZt7+lgFELcY\nUYBLaubb+D3Xgb0/W6pildW8EYgGkX+yx4PRq2WQQMRdk1+INmuRUVblEjPm2cDU\nBwIDAQAB\n-----END PUBLIC KEY-----", // 非对称秘钥明文
node接口调用代码
我是通过小程序点击事件想要查询支持同城配送的城市,但是报错提示为
{
errcode: 47001,
errmsg: 'data format error detail: [json错误] rid: 660a1e30-1fb6f74b-724a4b0f'
}
下边是我接口调用代码
// wx-用户信息
var express = require('express');
var router = express.Router();
var unit = require('../../unit/unit')
var signature = require('../../wxSignature/signature')
var { getData } = unit
var db = require("../../db"); //引入数据库封装模块
var { axiosGet, axiosPost } = unit;
var { getRequestEncryption, getResponseSignature } = signature;
// wx_查询支持同城配送的城市
router.get('/city/distribution/get', async (req, res) => {
let { iv, encryptedData, code } = req.body
let list = await axiosGet(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${db.wx._appid}&secret=${db.wx._secret}`,);
console.log(list.data.access_token);
let ctx1 = {
local_sym_key: db.wx._AES256_GCM_Key,
local_sym_sn: db.wx._AES256_GCM_Sn,
local_appid: db.wx._appid,
url_path: "https://api.weixin.qq.com/cgi-bin/express/intracity/getcity"
};
let reqs1 = {
service_trans_id: db.wx._service_trans_id,
}
let requestEncryption = getRequestEncryption(ctx1, reqs1);
let ctx2 = {
local_private_key: db.wx._RSAwithSHA256_Key,
local_sn: db.wx._RSAwithSHA256_Sn,
local_appid: db.wx._appid,
url_path: "https://api.weixin.qq.com/cgi-bin/express/intracity/getcity"
};
let reqs2 = requestEncryption
let responseSignature = getResponseSignature(reqs2)
let datas = await axiosPost(`https://api.weixin.qq.com/cgi-bin/express/intracity/getcity?access_token=${list.data.access_token}`,
responseSignature,
{
'Content-Type': "application/json;charset=utf-8",
'Accept': "application/json"
}
);
console.log(datas.data);
// {
// errcode: 47001,
// errmsg: 'data format error detail: [json错误] rid: 660a1e30-1fb6f74b-724a4b0f'
// }
})
module.exports = router;
下边是signature.js
// AES256_GCM
// 服务端api签名指南
const crypto = require("crypto")
var db = require("../db"); //引入数据库封装模块
module.exports = {
// 获取请求加密
getRequestEncryption: function (ctx, req) {
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
}
var ctx = ctx
var req = req
let res = getNewReq(ctx, req)
return res
},
// 获取请求签名
getResponseSignature: function async(reqs) {
// 仅做演示,敏感信息请勿硬编码
function getCtx() {
let ctx = {
local_private_key: db.wx._AES256_GCM_Key,
local_sn: db.wx._AES256_GCM_Sn,
local_appid: db.wx._appid,
url_path: "https://api.weixin.qq.com/wxa/getuserriskrank"
}
return ctx
}
function getReq() {
let req = reqs
return req
}
function getSignature(ctx, req) {
const { local_private_key, local_sn, local_appid, url_path } = ctx // 开发者本地信息
const { req_ts, req_data } = req // 待请求API数据
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 // salt长度,需与SHA256结果长度(32)一致
}
const sig_buffer = ss_buffer = crypto.Sign(
'RSA-SHA256',
data_buffer,
key_obj
)
const sig = sig_buffer.toString('base64')
return sig
/*
最终请求头字段
{
"Wechatmp-Appid": local_appid,
"Wechatmp-TimeStamp": req_ts,
"Wechatmp-Signature": sig,
}
*/
}
const ctx = getCtx()
const req = getReq()
let ress = getSignature(ctx, req)
return ress
},
}
下边是封装的post方法
var db = require("../db"); //引入数据库封装模块
//文件路由处理函数
const fs = require('fs')
const path = require('path')
const { default: axios } = require("axios");
module.exports = {
// 封装get请求
axiosGet: async function (url, params, headers) {
return new Promise((resolve, reject) => {
axios
.get(url, params,
{
headers: headers ? headers : {}
}
)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
},
// 封装post请求方法
axiosPost: async function (url, params, headers) {
return new Promise((resolve, reject) => {
axios
.post(url, params,
{
headers: headers ? headers : {}
}
)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
},
}
请加一下大佬这个错误的解决方法,还是说我请求签名加密的逻辑就有问题?
{
errcode: 47001,
errmsg: 'data format error detail: [json错误] rid: 660a1e30-1fb6f74b-724a4b0f'
}
这里提示很明显了,post的数据不是json。一方面检查一下json的数据格式,另一方面在请求header里面加上content-type,详细看一下同城配送文档
如下图,是没有封装的axios,但依然是47001