收藏
评论

v3图片上传接口java代码(HttpURLConnection实现)

折腾了一天,终于把这个图片接口(https://api.mch.weixin.qq.com/v3/merchant/media/upload)调通了。看到社区里面有不少小伙伴遇到了一样的问题,这里简单分享一下我的测试代码。因为我是用java开发的,所以下面内容的代码示例都是java的。

 水平有限,如有错漏之处,请多多指教。

public class uploadFileTest {
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
             
        try {
              
            // 换行符
            String LINE_END = "\r\n";
            String PREFIX = "--";
            // 定义数据分隔线
            String BOUNDARY = "";
             
            //商户号
            String mchid = "";
            //证书序列号
            String serial_no = "";
            //商户私钥(拷贝apiclient_key.pem文件里-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----之间的内容)
            String rsaPrivateKeyFile = "";
            //微信支付平台公钥文件
            String rsaPublicKey = "";
             
            //时间戳
            String timestamp = Long.toString(System.currentTimeMillis()/1000);
            //随机数
            String nonce_str = "";
             
            //图片文件
            String filePath = "";//文件路径
            File file = new File(filePath);
            String filename = file.getName();//文件名
            String fileSha256 = DigestUtils.sha256Hex(new FileInputStream(file));//文件sha256值
             
            //拼签名串
            StringBuffer sb = new StringBuffer();
            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\":\""+filename+"\",\"sha256\":\""+fileSha256+"\"}").append("\n");
            System.out.println("签名原串:"+sb.toString());
             
            //计算签名
            String sign = new String(Base64.encodeBase64(signRSA(sb.toString(),rsaPrivateKey)));
            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();
            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(verifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), rsaPublicKeyFile)) {
                System.out.println("签名验证成功");
            } else {
                System.out.println("签名验证失败");
            }
  
        } catch (Exception e) {
            System.out.println("发送POST请求异常!" + e);
            e.printStackTrace();
        }
 
    }
     
    
 
}


最后一次编辑于  2019-09-17
收藏

13 个评论

  • 曼玉
    曼玉
    2019-09-05


    这里是不是还有拼接一个append(PREFIX)

    2019-09-05
    赞同
    回复 2
    • test
      test
      2019-09-06
      按我的代码示例来实现就可以,我验证过是可以的。
      2019-09-06
      回复
    • 2019-09-20
      不需要的
      2019-09-20
      回复
  • 我是你的白衣少年
    我是你的白衣少年
    2019-09-02

    公钥跟私钥 都是要用pem密钥文件吗

    2019-09-02
    赞同
    回复 1
    • 2019-09-03
      不需要,从p12文件读出来的私钥也可以用。
      2019-09-03
      回复
  • 2019-08-31

    String fileSha256 = DigestUtils.sha256Hex(new FileInputStream(file));//文件sha256值

    签名是16进制串吗?不是Base64吗?

    2019-08-31
    赞同
    回复 3
    • test
      test
      2019-09-02
      这个只是计算文件的摘要,你也可以通过在线的工具https://www.it399.com/FileHash来检查一下你代码算出来的文件摘要是否正确
      2019-09-02
      回复
    • 2019-09-03回复test
      学习了!刚做了测试,发现filename含中文时,微信会验签不通过。看来他们验签的时候没有指定签名远串的编码!
      2019-09-03
      回复
    • test
      test
      2019-09-06回复
      我试了一下,把写入文件内容的out.writeBytes(string)改成 out.write(string.getBytes())就可以解决文件名中文的问题,示例代码我已经改过来了
      2019-09-06
      回复

正在加载...

登录 后发表内容