收藏
回答

V3接口的下载账单API 的签名以及验签问题?

问题描述:下载账单API 在调用后一直报错 400,检查是签名问题

需求结果是: 能拿到返回的流或者 response.getEntity().getContent()里的json 串 或者byte[]


2022-08-02 15:38:18 |DEBUG| com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials [68] | authorization token=[mchid="公司服务商的mchid",nonce_str="NzWT1hBVAO3krFhTuh7pGZLR9XWx4ORu",timestamp="1659425898",serial_no="公司服务商的的序列号",signature="LRCxDGacoxLQpYNEQaN/pDbuU1VjysywFHN1ZlZstygrZdFnjlYtrApBRPb+dM0jrohAlB3ix5RiKFrbZ4wXlKRrUTWg45aYsS+QdyGkOKwqcN7AKSfqqALluuGuni28Mnx5CFq9DyIVfBM3NfPf6GObzQC/qeJib6LvBI/XukwLRNpC1P5D+ADYrY26FmqM5piOGfrqDFIJ6SfiEKKeagNhNYNJO5voBzPejdzJdNAx99TDKO0r9y/rly2TSUDrUhpO057hxyBilV0oiIpheHPV2t9hmxGIDPoLoXicqfeCPZQI5ctKSWGe4ySZnoHSRB3OPAuGhP8vsvJsHXU/PA=="]
2022-08-02 15:38:18 |ERROR| com.wechat.pay.contrib.apache.httpclient.SignatureExec [95] | 应答的状态码不为200-299。status code[400]	request headers[[Authorization: WECHATPAY2-SHA256-RSA2048 mchid="公司服务商的mchid",timestamp="1659425891",nonce_str="8a44047dabe64cf79cc501faa17032b1",serial_no="公司服务商的的序列号",signature="Mpyw0flcxq4rLAr1rlydR3bwhANJMdK0CUrR8Vn02DxtC+QxBtn8gCg68k4ZweFUvE8GFt/DpInEztO4tVMhAqLVmWRC1WyFtGePvbdKtHT9G6LKo5w6glTixVa5CdNQGrQ8h8ye63o1QWnR9BmDD06rIiTaC9CRRlhclQ6wpIUNj6QbdPG4c7CO+a3e/n01WavapoqE75XxyRo7YMgt791XSw9u+gq01DBf9D2yp2Eme+pWReE1LTnQB21j9Ot6nwxWSwawYJeAdwkUG81VgAwoNw4gVLpmhybwXqXgNwt/fEUf7uZ2kVOYUPLoIR0WGYHb2pPAfLjKEbw0k1bs4g==", Authorization: WECHATPAY2-SHA256-RSA2048 mchid="公司服务商的mchid",nonce_str="NzWT1hBVAO3krFhTuh7pGZLR9XWx4ORu",timestamp="1659425898",serial_no="公司服务商的的序列号",signature="LRCxDGacoxLQpYNEQaN/pDbuU1VjysywFHN1ZlZstygrZdFnjlYtrApBRPb+dM0jrohAlB3ix5RiKFrbZ4wXlKRrUTWg45aYsS+QdyGkOKwqcN7AKSfqqALluuGuni28Mnx5CFq9DyIVfBM3NfPf6GObzQC/qeJib6LvBI/XukwLRNpC1P5D+ADYrY26FmqM5piOGfrqDFIJ6SfiEKKeagNhNYNJO5voBzPejdzJdNAx99TDKO0r9y/rly2TSUDrUhpO057hxyBilV0oiIpheHPV2t9hmxGIDPoLoXicqfeCPZQI5ctKSWGe4ySZnoHSRB3OPAuGhP8vsvJsHXU/PA==", Host: api.mch.weixin.qq.com, Connection: Keep-Alive, User-Agent: WechatPay-Apache-HttpClient/0.4.8 (Windows 10/10.0) Java/1.8.0_121, Accept-Encoding: gzip,deflate]]

第一个API:调用地址: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_11.shtml (申请分账账单API )

调用后返回 结果 如下:(正常返回下载地址)

//调用微信API 申请帐单API
WXDimensionResponseVo wxDimensionAPI = wxPay.getWXDimensionAPI(wxDimensionVo);

第二个API:调用地址: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter8_1_12.shtml(下载地址)

调用过程如下:(异常出现)

//调用微信API 下载文件API
WXBillExcl wXBillExcl = wxPay.getWXDownloadBillingAPI(wxDimensionAPI);
/**
 * 请求方式:GET
 * param:hash_type  哈希类型
 * param:hash_value 哈希值
 * param:download_url  下载地址
 * author:wzq
 * 作用:下载账单API

 * @return API返回数据
 * @throws Exception
 */
public WXBillExcl  getWXDownloadBillingAPI(WXDimensionResponseVo wXDimensionResponseVo) throws WXAPIException, IOException {
    InputStream inputStream = downloadV3(URI.create(wXDimensionResponseVo.getDownloadUrl()));
    FileOutputStream fos = new FileOutputStream("d:h3.xls");
    byte[] b = new byte[1024];
    int length;
    while ((length = inputStream.read(b)) > 0) {
        fos.write(b, 0, length);
    }
    WXBillExcl wxBillExcl = getWXExcl(inputStream);
    inputStream.close();
    fos.close();
    System.out.println("执行完成" + inputStream);
    return wxBillExcl;
}
/**
 * param:url
 * wx v3标准签名
 * wzq
 * */
public  InputStream downloadV3(URI url) throws WXAPIException,IOException {
    HttpGet httpGet = null;
    try {
        httpGet = new HttpGet(url);
        httpGet.addHeader("Authorization",schema+" "+ getToken("GET",HttpUrl.parse(url.toString()),""));
        CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpGet);
        int statusCode = response.getStatusLine().getStatusCode();
        if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
            return response.getEntity().getContent();
        }
    } catch (IOException e) {
        System.out.println("\n【请求地址:" + url + "\n【异常信息】:" + e.getMessage());
    } catch (Exception e) {
        System.out.println("\n【请求地址:" + url + "\n【异常信息】:" + e.getMessage());
        throw (e instanceof WXAPIException) ? (WXAPIException) e : new WXAPIException(e.getMessage(), e);
    } finally {
        httpGet.releaseConnection();
    }
    return null;
}
private final static String schema = "WECHATPAY2-SHA256-RSA2048";

public String getToken(String method, HttpUrl url, String body) {
    Long timestamp = System.currentTimeMillis() / 1000;
    String nonceStr = UUID.randomUUID().toString().replace("-","");
    String message = buildMessage(method, url, timestamp, nonceStr, body);
    String signature = message;
    try {
        signature = sign(message.getBytes("utf-8"));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    return "mchid=\"" + sp_mchid + "\","
            + "timestamp=\"" + timestamp + "\","
            + "nonce_str=\"" + nonceStr + "\","
            + "serial_no=\"" + sp_mchSerialNo + "\","
            + "signature=\"" + signature + "\"";
}

public String sign(byte[] message) {
    try {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(PemUtil.loadPrivateKey(new ByteArrayInputStream(sp_privateKey.getBytes("utf-8"))));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    } catch (SignatureException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return null;
}

/**
 * 签名的方法
* */
public String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
    String canonicalUrl = url.encodedPath();
    if (url.encodedQuery() != null) {
        canonicalUrl += "?" + url.encodedQuery();
    }

    return method + "\n"
            + canonicalUrl + "\n"
            + timestamp + "\n"
            + nonceStr + "\n"
            + body +"\n";
}


最后一次编辑于  2022-08-02
回答关注问题邀请回答
收藏

1 个回答

  • Savior
    Savior
    2022-08-02

    报错日志

    2022-08-02
    有用
    回复 1
    • Savior
      Savior
      2022-08-02
      固定时间后的Long timestamp = 1659426703l; 生成的还是两个时间。,然后是不同的时间戳
      2022-08-02
      回复
登录 后发表内容