nodejs微信支付小微商户申请入驻时,如何实现图片上传接口

微信支付小微商户可以通过小程序《微信买单服务商助手》来进件,也可以通过API接口来进件(详情可查阅小微商户专属接口文档)。

通过API接口进件前需要先在商户资料中的身份证照片和门店照片通过图片上传接口上传到微信的服务器,并获取media_id。

图片上传接口文档是这样写的:



上传图片

服务商操作员调用 API 接口,上传证件照片。支持 jpeg、jpg、bmp、png 格式。通过 POST 表单来调用该接口,表单媒体文件 id 为 media,需有 filename、filelength、content-type 等信息,请求报文的内容需以 multipart/form-data 方式提交。 URL 地址:https://api.mch.weixin.qq.com/secapi/mch/uploadmedia 

 

是否需要证书

 

请求参数

字段名

变量名

必填

类型

示例值

描述

商户号

mch_id

String(32)

 

银行商户号或渠道号

媒体文件

media

String(256)

 

form-data 中媒体文件标识,有 filename、filelength、content-type 等信息。不参与签名计算

媒体文件内容 hash 值

media_hash

String(32)

 

根据媒体文件内容进行MD5 计算后的值

签名

sign

String(32)

D675A1E471DBF7C0

B1AC5883B5BDA9EF

 

签名方式

sign_type

String(10)

HMAC-SHA256

 HMAC-SHA256 加密方式,其他或者不填为MD5方式

 

返回参数

字段名 

变量名

必填

类型

示例值

描述

返回状态码

return_code

String(16)

SUCCESS

 

返回信息

return_msg

String(128)

签名失败

 

以下字段在 return_code 为 SUCCESS 的时候有返回

变量名

必填

类型

示例值

业务结果

result_code

String(32)

 

媒体标识 Id

media_id

String(256)

9UYfXi-WMUhgWXvJtEw4_g

Ble_EfrD_pIL0bS8GAsK8

签名

sign

String(32)

 

错误代码

err_code

String(32)

INVALID_REQUEST

错误代码描述

err_code_des

String(128)

商户号信息有误,请检查修改后重试

 

请求示例

curl --cert ./apiclient_cert.pem --key ./apiclient_key.pem -F'mch_id=1000000000' -F 'media_hash=709d1e858d2ef9d0501cc053668b2872' -F 'sign=D675A1E471DBF7C0B1AC5883B5BDA9EF' -F '[email protected]' https://api.mch.weixin.qq.com/secapi/mch/uploadmedia

 

响应示例


<xml>
    <return_code><![CDATA[SUCCESS]]></return_code>
    <return_msg><![CDATA[OK]]></return_msg>
    <result_code><![CDATA[SUCCESS]]></result_code>
    <media_id><![CDATA[9UYfXi-WMUhgWXvJtEw4_gBle_EfrD_pIL0bS8GAsK8]]></media_id>
    <sign><![CDATA[D675A1E471DBF7C0B1AC5883B5BDA9EF]]></sign>
</xml>

 

错误码

错误码 名称 描述 解决方案

INVALID_REQUEST

不支持 http get方法

请使用 post 方法,请检查后重新提交

检查输入参数

INVALID_REQUEST

xml 格式错误

xml 参数格式错误,请检查后重新提交

 

SIGNERROR

验签错误

签名校验失败,请检查后重试

 

INVALID_REQUEST

需要证书

获取客户端证书序列号失败

获取客户端证书特征名称(DN)域失败

证书校验失败,请检查后重试

检查证书

PARAM_ERROR

参数错误

参数填写有误,请检查后重试

人工检查过滤

PARAM_ERROR

图片文件错误

图片格式不正确,请检查后重新提交

图片大小不能超过 2M,请检查后重新提交

图片 Hash 值有误,请检查后重新提交

检查图片

PARAM_ERROR

商户号错误

商户号 mchid 有误,请检查后重试

检查商户号是否正确

INVALID_REQUEST

调用权限

暂无权限,请检查后重试

检查权限

FREQUENCY_LIMITED

频率限制

操作过快,请稍后重试

放慢上传频率

SYSTEMERROR

上传图片失败

上传图片失败,请稍后重试

联系微信支付客服



代码如下,其中getXML为解析XML的函数,请自行完成:


var https = require("https");
var crypto = require('crypto');
var hmac_sha256 = require("crypto-js/hmac-sha256"); //请自行 npm install crypto-js

var uploadMedia = function(filePath, fname, fn){	
    //要上传的文件完整路径
	var cfile = filePath + "\\" + fname;	
	var mch_id = "服务商商户号";
	var wkey = "API密钥或APIv3密钥";
	//读取图片内容
	var buffer = fs.readFileSync(cfile);	
	var fsize = Buffer.byteLength(buffer);
    //获取图片hash值(MD5)
	var fsHash = crypto.createHash('md5');
	fsHash.update(buffer);
	var fmd5 = fsHash.digest('hex');
    //对参数进行hmac_sha256签名
    var signData = 'mch_id=' + mch_id + '&media_hash=' + fmd5 + '&sign_type=HMAC-SHA256' + "&key=" + wkey;
	var sign = hmac_sha256(signData, wkey) + ''; 
	sign = sign.toUpperCase();	
    
    //开始构建包头内容(包头需要传入必须的参数,如:mch_id、media_hash、sign、sign_type)
	var boundaryKey = Math.random().toString(16); //随机数,目的是防止上传文件中出现分隔符导致服务器无法正确识别文件起始位置
	var payload = '--' + boundaryKey + '\r\n'
      + 'Content-Disposition:form-data; name="mch_id"\r\n\r\n'  
      + '' + mch_id + '\r\n' 
      + '--' + boundaryKey + '\r\n'
      + 'Content-Disposition:form-data; name="media_hash"\r\n\r\n'  
      + '' + fmd5 + '\r\n' 
      + '--' + boundaryKey + '\r\n'
      + 'Content-Disposition:form-data; name="sign"\r\n\r\n'  
      + '' + sign + '\r\n' 
      + '--' + boundaryKey + '\r\n'
      + 'Content-Disposition:form-data; name="sign_type"\r\n\r\n'  
      + 'HMAC-SHA256\r\n' 
      + '--' + boundaryKey + '\r\n'
      + 'Content-Disposition:form-data; name="media"; filename="' + fname + '"\r\n'  
      + 'Content-Type:image/png\r\n' 
      + 'Content-Transfer-Encoding:binary\r\n\r\n';
    //开始构建包尾内容
    //注意前面必须且只能有一个换行符,否则会返回“图片 Hash 值有误,请检查后重新提交”的错误提示
    //后面必须且只能有各个换行符,否则会返回“参数填写有误,请检查后重试”的错误提示
    var enddata  = '\r\n--' + boundaryKey + '--\r\n';
    var rq = https.request({
        host: 'api.mch.weixin.qq.com',
		port: 443,
		pfx:fs.readFileSync('./cert/' + mch_id + '.pfx'),
		passphrase:mch_id,
		path: '/secapi/mch/uploadmedia',
		method: 'POST'
    },function(ress){
        var str='';
        ress.on('data',function(buf){
            str+=buf;//用字符串拼接
        });
        ress.on('end',function(){
    	    if(getXML(str, "return_code") != "SUCCESS"){
    		    if(fn) fn('{"code":-1, "msg":"无法上传图片《' + fname + '》(' + getXML(str, "return_msg") + ')"}');
    		    return;
    	    }
    	    if(getXML(str, "result_code") != "SUCCESS"){
    		    if(fn) fn('{"code":-1, "msg":"无法上传图片《' + fname + '》(' + getXML(str, "err_code_des") + ')"}');
    		    return;
    	    }
    	    if(fn) fn(getXML(str, "media_id"));
        });
    });
    //写header头,表示包识别符,和包大小
    rq.setHeader('Content-Type', 'multipart/form-data; boundary='+boundaryKey+'');
    rq.setHeader('Content-Length', Buffer.byteLength(new Buffer(payload, 'binary'))+Buffer.byteLength(new Buffer(enddata, 'binary'))+fsize);    
    //发包
    rq.write(Buffer.concat([new Buffer(payload, 'binary') , buffer , new Buffer(enddata, 'binary')]) );
  
    rq.on('error',function(err){
        if(fn){fn('{"code":-1, "msg":"无法上传图片《' + fname + '》(' + err.message + ')"}')}
    });	
    rq.end();
}

猜你喜欢

转载自blog.csdn.net/yyoinge/article/details/81564094