收藏
回答

使用同城配送功能,node接入api加密签名后,调用查询支持同城配送的城市报错47001?

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'
 }
回答关注问题邀请回答
收藏

1 个回答

  • I'm Henry
    I'm Henry
    04-01

    这里提示很明显了,post的数据不是json。一方面检查一下json的数据格式,另一方面在请求header里面加上content-type,详细看一下同城配送文档

    04-01
    有用
    回复 3
    • 一百八十块
      一百八十块
      04-01
      你好,我确实在碰撞post中设置了规定的headers
      如下图,是没有封装的axios,但依然是47001
      04-01
      回复
    • I'm Henry
      I'm Henry
      04-01回复一百八十块
      辛苦检查一下代码实现,实际上没有任何数据请求到微信后台
      04-01
      回复
    • 一百八十块
      一百八十块
      04-01回复I'm Henry
      你好,我修改代码后47001错误码不再出现,但是出现了40234,签名错误的状态。是不是因为我的秘钥不是PKCS#1格式的呢
      04-01
      回复
登录 后发表内容