电商收付通系列④,图片预上传,生成MediaID

简介: 部分微信支付业务指定商户需要使用图片上传 API来上报图片信息,从而获得必传参数的值:图片MediaID。即电商收付通接口有涉及到需要传图片的参数,不可以直接传图片文件,均需要通过指定的图片上传接口获取MediaID,再把MediaID传给相应的字段。比如二级商户进件接口需要上传营业执照,字段是business_license_copy,那么需要预先生成MediaID,将MediaID的值传business_license_copy。

1、介绍

部分微信支付业务指定商户需要使用图片上传 API来上报图片信息,从而获得必传参数的值:图片MediaID。即电商收付通接口有涉及到需要传图片的参数,不可以直接传图片文件,均需要通过指定的图片上传接口获取MediaID,再把MediaID传给相应的字段。比如二级商户进件接口需要上传营业执照,字段是business_license_copy,那么需要预先生成MediaID,将MediaID的值传business_license_copy。

2、Authorization签名

文档地址:
https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/chapter3_1.shtml
注意:参与签名计算的请求主体为meta的json串:{ "filename": "file.jpg", "sha256": "hjkahkjsjkfsjk78687dhjahdajhk" },文档说商户上传的媒体图片的名称,商户自定义,必须以JPG、BMP、PNG为后缀,亲测JPEG也可以上传成功
待签名串:

String timestamp = Long.toString(System.currentTimeMillis()/1000);
//随机数
String nonce_str = UuidUtils.randomUUID();
//图片文件
String filePath ="图片位置.jpg";//文件路径
File file = new File(filePath);
String filename = file.getName();//文件名
String fileSha256 = DigestUtils.sha256Hex(new FileInputStream(file));//文件sha256值
//拼签名串
StringBuilder sb =new StringBuilder();
sb.append("POST").append("\n");
sb.append("/v3/merchant/media/upload").append("\n");
sb.append(timestamp).append("\n");
sb.append(nonce_str).append("\n");
sb.append("{\"filename\":\"").append(filename).append("\",\"sha256\":\"").append(fileSha256).append("\"}").append("\n");
System.out.println("签名原串:"+sb.toString());

计算签名sign

//计算签名
String sign =new String(Base64.encodeBase64(signRSA(sb.toString(),rsaPrivateKeyFile)));
System.out.println("签名sign值:"+sign);

拼接Authorization

//拼装http头的Authorization内容
String authorization ="WECHATPAY2-SHA256-RSA2048 mchid=\""+mchid+"\",nonce_str=\""+nonce_str+"\",signature=\""+sign+"\",timestamp=\""+timestamp+"\",serial_no=\""+serial_no+"\"";
System.out.println("authorization值:"+authorization);

image.png

3、添加HTTP头

//接口URL
URL url =new URL("https://api.mch.weixin.qq.com/v3/merchant/media/upload");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置为POST
conn.setRequestMethod("POST");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求头参数
conn.setRequestProperty("Charsert","UTF-8");
conn.setRequestProperty("Accept","application/json");
conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
conn.setRequestProperty("Authorization", authorization);

4.添加body

DataOutputStream dos =new DataOutputStream(conn.getOutputStream());

//拼装请求内容第一部分
StringBuilder strSb =new StringBuilder();
strSb.append(PREFIX).append(BOUNDARY).append(LINE_END)
      .append("Content-Disposition: form-data; name=\"meta\";" + LINE_END)
      .append("Content-Type: application/json; " + LINE_END)
      .append(LINE_END)// 空行
      .append("{\"filename\":\""+filename+"\",\"sha256\":\""+fileSha256+"\"}")
      .append(LINE_END);
dos.write(strSb.toString().getBytes());

dos.flush();

//拼装请求内容第二部分
StringBuilder fileSbStart =new StringBuilder();
fileSbStart.append(PREFIX).append(BOUNDARY).append(LINE_END)
      .append("Content-Disposition: form-data; name=\"file\"; filename=\""+ filename+"\";" + LINE_END)
      .append("Content-Type: image/jpeg" + LINE_END)
      .append(LINE_END);// 空行
dos.write(fileSbStart.toString().getBytes());

dos.flush();

//文件二进制内容
InputStream is =new FileInputStream(file);
byte[] buffer =new byte[1024];
int len =0;
while ((len = is.read(buffer)) != -1){
  dos.write(buffer,0,len);
}
is.close();

//拼装请求内容结尾
StringBuilder fileSbEnd =new StringBuilder();
fileSbEnd.append(LINE_END)
        .append(PREFIX).append(BOUNDARY).append(PREFIX)
        .append(LINE_END);

dos.write(fileSbEnd.toString().getBytes());

dos.flush();
dos.close();

image.png

5.获取结果验签

//打印返回头信息
System.out.println("接口返回头信息:");
Map<String, List<String>> responseHeader = conn.getHeaderFields();
for (Map.Entry<String, List<String>> entry : responseHeader.entrySet()) {
    System.out.println(entry.getKey()+":" + entry.getValue());
}

//打印返回内容
int responseCode = conn.getResponseCode();
System.out.println("responseCode:"+responseCode);
String rescontent = "";
if((responseCode+"").startsWith("2")){
    //成功
rescontent =new String(InputStreamTOByte(conn.getInputStream()));
System.out.println("图片上传成功:"+rescontent);
}else{
//失败
rescontent =new String(InputStreamTOByte(conn.getErrorStream()));
System.out.println("图片上传失败:"+rescontent);
}

//验证微信支付返回签名
String Wtimestamp = responseHeader.get("Wechatpay-Timestamp").get(0);
String Wnonce = responseHeader.get("Wechatpay-Nonce").get(0);
String Wsign = responseHeader.get("Wechatpay-Signature").get(0);
//拼装待签名串
StringBuffer ss =new StringBuffer();
ss.append(Wtimestamp).append("\n");
ss.append(Wnonce).append("\n");
ss.append(rescontent).append("\n");
//验证签名
if(SignUtils.v3VerifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), "微信支付平台证书.pem")) {
    System.out.println("签名验证成功");
}else {
    System.out.println("签名验证失败");
}

6、发送请求

try {

    // 换行符
    String LINE_END ="\r\n";
    String PREFIX ="--";
    // 定义数据分隔线
    String BOUNDARY = "----------" + System.currentTimeMillis();

    //商户号
    String mchid ="商户号";
    //证书序列号
    String serial_no ="证书序列号";
    //商户私钥
    String rsaPrivateKeyFile = "商户私钥";
    //时间戳
    String timestamp = Long.toString(System.currentTimeMillis()/1000);
    //随机数
    String nonce_str = UuidUtils.randomUUID();

    //图片文件
    String filePath ="图片位置.jpg";//文件路径
    File file = new File(filePath);
    String filename = file.getName();//文件名
    String fileSha256 = DigestUtils.sha256Hex(new FileInputStream(file));//文件sha256值

    //拼签名串
    StringBuilder sb =new StringBuilder();
    sb.append("POST").append("\n");
    sb.append("/v3/merchant/media/upload").append("\n");
    sb.append(timestamp).append("\n");
    sb.append(nonce_str).append("\n");
    sb.append("{\"filename\":\"").append(filename).append("\",\"sha256\":\"").append(fileSha256).append("\"}").append("\n");
    System.out.println("签名原串:"+sb.toString());
    
    //计算签名
    String sign =new String(Base64.encodeBase64(signRSA(sb.toString(),rsaPrivateKeyFile)));
    System.out.println("签名sign值:"+sign);
  
    //拼装http头的Authorization内容
    String authorization ="WECHATPAY2-SHA256-RSA2048 mchid=\""+mchid+"\",nonce_str=\""+nonce_str+"\",signature=\""+sign+"\",timestamp=\""+timestamp+"\",serial_no=\""+serial_no+"\"";
    System.out.println("authorization值:"+authorization);
  
    //接口URL
    URL url =new URL("https://api.mch.weixin.qq.com/v3/merchant/media/upload");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    // 设置为POST
    conn.setRequestMethod("POST");
    // 发送POST请求必须设置如下两行
    conn.setDoOutput(true);
    conn.setDoInput(true);
    conn.setUseCaches(false);
    // 设置请求头参数
    conn.setRequestProperty("Charsert","UTF-8");
    conn.setRequestProperty("Accept","application/json");
    conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
    conn.setRequestProperty("Authorization", authorization);

    DataOutputStream dos =new DataOutputStream(conn.getOutputStream());
    
//拼装请求内容第一部分
    StringBuilder strSb =new StringBuilder();
    strSb.append(PREFIX).append(BOUNDARY).append(LINE_END)
            .append("Content-Disposition: form-data; name=\"meta\";" + LINE_END)
            .append("Content-Type: application/json; " + LINE_END)
            .append(LINE_END)// 空行
            .append("{\"filename\":\""+filename+"\",\"sha256\":\""+fileSha256+"\"}")
            .append(LINE_END);
    dos.write(strSb.toString().getBytes());

    dos.flush();

    //拼装请求内容第二部分
    StringBuilder fileSbStart =new StringBuilder();
    fileSbStart.append(PREFIX).append(BOUNDARY).append(LINE_END)
            .append("Content-Disposition: form-data; name=\"file\"; filename=\""+ filename+"\";" + LINE_END)
            .append("Content-Type: image/jpeg" + LINE_END)
            .append(LINE_END);// 空行
    dos.write(fileSbStart.toString().getBytes());

    dos.flush();

    //文件二进制内容
    InputStream is =new FileInputStream(file);
    byte[] buffer =new byte[1024];
    int len =0;
    while ((len = is.read(buffer)) != -1){
        dos.write(buffer,0,len);
    }
    is.close();

    //拼装请求内容结尾
    StringBuilder fileSbEnd =new StringBuilder();
    fileSbEnd.append(LINE_END)
            .append(PREFIX).append(BOUNDARY).append(PREFIX)
            .append(LINE_END);

    dos.write(fileSbEnd.toString().getBytes());

    dos.flush();
    dos.close();

    //接收返回
    //打印返回头信息
    System.out.println("接口返回头信息:");
    Map<String, List<String>> responseHeader = conn.getHeaderFields();
    for (Map.Entry<String, List<String>> entry : responseHeader.entrySet()) {
        System.out.println(entry.getKey()+":" + entry.getValue());
    }

    //打印返回内容
    int responseCode = conn.getResponseCode();
    System.out.println("responseCode:"+responseCode);
    String rescontent = "";
    if((responseCode+"").startsWith("2")){
        //成功
    rescontent =new String(InputStreamTOByte(conn.getInputStream()));
    System.out.println("图片上传成功:"+rescontent);
      }else{
          //失败
          rescontent =new String(InputStreamTOByte(conn.getErrorStream()));
          System.out.println("图片上传失败:"+rescontent);
      }

      //验证微信支付返回签名
      String Wtimestamp = responseHeader.get("Wechatpay-Timestamp").get(0);
      String Wnonce = responseHeader.get("Wechatpay-Nonce").get(0);
      String Wsign = responseHeader.get("Wechatpay-Signature").get(0);
      //拼装待签名串
      StringBuffer ss =new StringBuffer();
      ss.append(Wtimestamp).append("\n");
      ss.append(Wnonce).append("\n");
      ss.append(rescontent).append("\n");
      //验证签名
      if(SignUtils.v3VerifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), "微信支付平台证书.pem")) {
          System.out.println("签名验证成功");
      }else {
          System.out.println("签名验证失败");
      }
        return JSONObject.parseObject(rescontent);
    } catch (Exception e) {
        System.out.println("发送POST请求异常!" + e);
        e.printStackTrace();
    }

      return null;
  }

image.png

7、测试

POST
/v3/merchant/media/upload
1585302190
20962176ac337f69cbb1548ada1fe448
{"filename":"图片位置.jpg","sha256":"75e6d36f9e4d5738bfafbccb298924108022cb89fa6fb94c58c877f83753174f"}

签名sign值:nnIQQbWurSmAxiS6gA6vPH6iaJSBbdJ8luvz97+8vRDfF9Z3SDtYMR79mMbyl2QhGYI1sERT3hlDone2HGvd3RnEHl8pmtOp8TiYoQfrTu1WpCKvjCdQJDnqkSSgVy5JBgR9J2in2G21pox5RTtRSktGMVBFAn3wcJuFjbtFkqMlt3bLP3/JTzvB1vGxHnuiZu8Lp8gDqY541U4IMr+KKtQlahsPKgNGhh5B9iocGyB0wNyjJkgtBic11YGjMTAvVeJYW3ZQmt6aIbyvHDyYb0taXWoH2lEGPIpsPOx7Myy8OWcvbM+Ze1uuEX+L7su+vXl1TALSuDgoEsUTelRr/w==
authorization值:WECHATPAY2-SHA256-RSA2048 mchid="1900000109",nonce_str="20962176ac337f69cbb1548ada1fe448",signature="nnIQQbWurSmAxiS6gA6vPH6iaJSBbdJ8luvz97+8vRDfF9Z3SDtYMR79mMbyl2QhGYI1sERT3hlDone2HGvd3RnEHl8pmtOp8TiYoQfrTu1WpCKvjCdQJDnqkSSgVy5JBgR9J2in2G21pox5RTtRSktGMVBFAn3wcJuFjbtFkqMlt3bLP3/JTzvB1vGxHnuiZu8Lp8gDqY541U4IMr+KKtQlahsPKgNGhh5B9iocGyB0wNyjJkgtBic11YGjMTAvVeJYW3ZQmt6aIbyvHDyYb0taXWoH2lEGPIpsPOx7Myy8OWcvbM+Ze1uuEX+L7su+vXl1TALSuDgoEsUTelRr/w==",timestamp="1585302190",serial_no="678C5D9A1FDBAC2C1291C65ADB22FDC2942F9CAE"
接口返回头信息:
Keep-Alive:[timeout=8]
null:[HTTP/1.1 200 OK]
Wechatpay-Timestamp:[1585302193]
Server:[nginx]
X-Content-Type-Options:[nosniff]
Connection:[keep-alive]
Date:[Fri, 27 Mar 2020 09:43:13 GMT]
Wechatpay-Serial:[911AFE1DC9C13FCCE6414B17A4927800A15A2E44]
Wechatpay-Nonce:[5f1e613ac12d8d3fd62144b402c09ce5]
Wechatpay-Signature:[GKc2009HtQD4Ld8AP8o/vmyRAO6C9kcCfpce90NL6eX44ov6qTNS25DYzh8GFqybq6ZBoSzZ2QZNFBD2NOCIcuUZ06d32ZtpdiVh7eOMRb8pRjO+R2DMHzm44ApU/KmGQlo8PlZm+SU1unDFeEtKJxL1b1ih4ndORqJeSXBQET1yCifB+yuic4hLOXMjk849F+pUg0M579t+8y8JM+7vPMTMenr7JdH2UihBiIKtQURTcW59QuDkeeomK/n2737e/MeXxZxOqkHqGNzWYiuI/gcAlcgNWSJ96KqD9J/pZPsJDEXnIu1408Q0BHJLeAyLquawtI9Mzxg1+8K64sOCL7==]
Cache-Control:[no-cache, must-revalidate]
Content-Length:[122]
Content-Language:[zh-CN]
Request-ID:[bnd0ak]
Content-Type:[application/json; charset=utf-8]
responseCode:200
图片上传成功:{"media_id":"VrvwA0PTBrBCnLiawyLnWFiF9pthhuBlt1FgxnXw80jOftpw9Nx-ujy185eULCvkESSdw702IHXFKAhaONWQpUkOfSsawMoOK4XuUrPNtNY"}
17:43:13.527 [main] INFO com.smartMap.media.common.weixin.ecommercepay.common.SignUtils - v3VerifyRSA result:签名验证成功
签名验证成功

image.png

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海

上一篇:电商收付通系列③,对微信应答或回调进行签名验证

相关文章
|
供应链 搜索推荐 数据挖掘
淘宝详情API接口:实现营销自动化的黄金通道
在当今的数字化时代,电子商务正在迅速发展,其中淘宝作为中国最大的电商平台之一,拥有着巨大的用户群体和丰富的商品资源。对于许多卖家来说,如何在这个巨大的市场中脱颖而出,营销策略是至关重要的。而淘宝详情API接口则为卖家提供了一个实现营销自动化的黄金通道。
发布宝贝提示“亲,您未通过食品资质备案所以无法新发商品”如何解决
亲,您未通过食品资质备案所以无法新发商品!根据《中华人民共和国食品安全法》要求,经营该类目下商品(食用农产品除外)需提供食品经营或食品生产资质,<a href='https://t.tb.cn/5CSyQjdLA5q33HBQElFNGd' target='_blank'>点击查看资质要求学习链接</a>,<a href='https://scportal.taobao.com/quali/portal.htm?source=taobao' target='_blank'>点击立即上传资质</a>,经营不同类型的食品,提交资质时,请您注意“经营范围”的选择。
|
4月前
|
安全 API Windows
支付系统13------支付系统的资料在技术库里的在线支付当中,怎样获取微信平台证书那?怎样获取微信平台证书那?第一步打开我们的微信支付平台的文档中心
支付系统13------支付系统的资料在技术库里的在线支付当中,怎样获取微信平台证书那?怎样获取微信平台证书那?第一步打开我们的微信支付平台的文档中心
|
6月前
|
数据采集 供应链 搜索推荐
API接口与商品数据:开启电商成功的新篇章
在当今数字化时代,电子商务(电商)已成为商业领域的重要组成部分。对于电商平台来说,能够高效地获取和管理商品数据是至关重要的。API(应用程序编程接口)接口作为一种允许不同软件系统之间进行通信的工具,为电商平台提供了获取商品数据的便捷途径。本文将探讨如何使用API接口获取商品数据,以及如何利用这些数据推动电商业务的成功。
|
安全 数据管理 测试技术
同城预约上门理疗推拿按摩系统功能开发实例源码规则解析
同城预约上门理疗推拿按摩系统功能开发实例源码规则解析
|
小程序 开发者
电商收付通,商户进件,上传身份证、营业执照自动识别相关信息
二级商户进件的时候,需要提交的资料不少,有一个繁琐的地方就是,不管选择哪种主体类型,都需要上传身份证人像面、身份证国徽面、身份证姓名、身份证号码、身份证居住地址、身份证开始时间和身份证结束时间这些要素。
249 0
电商收付通,商户进件,上传身份证、营业执照自动识别相关信息
|
API
电商收付通系列⑪ ,下载账单
电商收付通的账单分为交易账单和资金账单,两种账单获取方式相同,这里只举例获取交易账单。交易账单:微信支付按天提供交易账单文件,文件内包含交易相关的金额、时间、营销等信息,供商户核对订单、退款、银行到账等情况。资金账单:微信支付按天提供微信支付账户的资金流水账单文件,文件内包含该账户资金操作相关的业务单号、收支金额、记账时间等信息,供商户进行核对。
193 0
电商收付通系列⑪ ,下载账单
|
存储 数据可视化 API
电商收付通可视化进件二级商户,多功能升级
服务商账号参数在成后台可配置,随时修改,立即生效。更换服务商账号相关参数无需修改代码再次打包部署,更便捷。参数包括本系统应用名称、服务商平台商户号、商户号绑定的appId、服务商平台商户API证书序列号、服务商平台商户API证书位置路径、微信支付平台证书位置路径、微信支付平台apiV3密钥、微信支付回调通知地址。
145 0
电商收付通可视化进件二级商户,多功能升级
|
移动开发 安全 小程序
电商收付通系统,可视化进件二级商户
传统的电商平台都是在用户确认收货后再在一定的周期内结算给商户,就是采取平台先收款的方式,但这样不仅给电商平台带来税务的问题,还影响商户的资金安全。有了电商收付通,就不存在这样的问题了。
281 0
电商收付通系统,可视化进件二级商户
|
API
电商收付通系列⑥,商户进件之查询申请状态
查询申请状态API可按以下两种不同方式查询:通过申请单ID查询申请状态,通过业务申编号查询申请状态,两种不同查询方式返回结果相同。
177 0
电商收付通系列⑥,商户进件之查询申请状态