微信native方式支付中body为中文时签名错误解决方法
2015-07-01 16:03
966 查看
[java] view
plaincopyprint?
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 18px; font-weight: bold; background-color: rgb(255, 255, 255);"> </span>
最近在做在做微信支付中的native支付第二种支付方式,在请求参数时遇到了最大的问题就是,body(商品描述)为中文时,签名失败,为英文时签名成功。这个问题搞了好几天,没有搞定,今天终于搞定了,特此分享一哈。
其实就是一句话的问题: 把我们生成的xml请求参数转为字节数组后,用“ISO8859-1”编码格式进行编码为字符串,就可以解决问题了。
[java] view
plaincopyprint?
return new String(sb2.toString().getBytes(), "ISO8859-1");
=============================================================================================================
上面的已经可以解决问题。下面我只是说说更详细的解决步骤。
1. 首先我们来看看官方的接口文档:
认证方式:HTTPS讣证,退款和冲正接口调用需要商户证书(证书在审核邮件附件
中)
请求采用POST方式
提交和返回结果采用XML格式
字符集默讣使用UTF-8,请勿使用其它字符集
商户不微信之间的交互(特别是Native回调和支付通知回调),都需要验证签名
4.1.统一支付接口
URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
统一支付接口,可接叐JSAPI/NATIVE/APP下预支付订单,返回预支付订单号。
NATIVE支付返回二维码code_url。
注意:JSAPI 下单前需要调用登录授权接口(详细调用说明请点击打开链接)获叏到用户
的Openid。
![](http://img.blog.csdn.net/20141214183210162?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl3ZW5taW5nc2hpd28=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20141214183233625?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl3ZW5taW5nc2hpd28=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20141214183251812?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl3ZW5taW5nc2hpd28=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20141214183301502?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl3ZW5taW5nc2hpd28=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
我们只需要传递对应的参数,请求“https://api.mch.weixin.qq.com/pay/unifiedorder ”,把得到“code_url”生成二维码即可。
2. 定义个常量类用来存储请求值
我定义了一常量类,保存我们用到的参数值(这只是我的Demo,不是真实中的项目,所以这么用,真实中不能这么弄,这个在真实中最好有服务器端操作,我们需要的只是一个"code_url"而已)。
[java] view
plaincopyprint?
/**
* 请求需要的参数
* @author Administrator
*
*/
public class Constans {
//appid
public static String APPID = "wxd930ea5d5a258f4f";
public static String auth_code = genNonceStr();
public static String body = "霸气的小明(qiwenming)";
public static String device_info = "1000";
public static String mch_id = "1900000109";
public static String nonce_str = genNonceStr();
public static String out_trade_no = genNonceStr();
public static String spbill_create_ip = "127.0.0.1";
public static String notify_url = "http://www.baidu.com";
public static String total_fee = "1";
public static String trade_type = "NATIVE";
public static String private_key = "8934e7d15453e97507ef794cf7b0519d";
public static String key = "L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K";
//请求地址
public static String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
//生成随机字符串
private static String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
}
3.我们组织参数,生成请求参数(XML格式 )
这里分为2步:
第一步,我们把请求参数,按字典顺序存入到一个集合中;
第二步,我们把这些参数组装为xml格式的数据,并且完成签名的过程,这一步中最关键的是 我们要把生成的xml字符串,转为字节后,在使用“Isolates859-1”编码重新编码为字符串。
3.1按字典顺序存入到一个集合中:
[java] view
plaincopyprint?
<span style="font-size:18px;"><strong> </strong> </span><span style="font-size:14px;"> /**
* 把一个参数添加到 一个集合中,按字典顺序,这是为了后面生成 签名方便
*
* @return
*/
private String genProductArgs() {
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("appid", Constans.APPID));
packageParams.add(new BasicNameValuePair("appkey", Constans.key));
packageParams.add(new BasicNameValuePair("body", Constans.body));
packageParams.add(new BasicNameValuePair("input_charset", "UTF-8"));
packageParams.add(new BasicNameValuePair("mch_id", Constans.mch_id));
packageParams.add(new BasicNameValuePair("nonce_str",
Constans.nonce_str));
packageParams.add(new BasicNameValuePair("notify_url",
"http://www.baidu.com"));
packageParams.add(new BasicNameValuePair("out_trade_no",
Constans.out_trade_no));
packageParams.add(new BasicNameValuePair("spbill_create_ip",
Constans.spbill_create_ip));
packageParams.add(new BasicNameValuePair("total_fee", Constans.total_fee));
packageParams.add(new BasicNameValuePair("trade_type",
Constans.trade_type));
//调用genXml()方法获得xml格式的请求数据
return genXml(packageParams);
}</span><span style="font-size:18px;">
</span>
3.2生成XML格式参数,注意转码:
[java] view
plaincopyprint?
/**
* 生成xml格式的请求参数
*
* @param params
* 参数集合
* @return
*/
private String genXml(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
sb2.append("<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><xml>");
for (int i = 0; i < params.size(); i++) {
// sb是用来计算签名的
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
// sb2是用来做请求的xml参数
sb2.append("<" + params.get(i).getName() + ">");
sb2.append(params.get(i).getValue());
sb2.append("</" + params.get(i).getName() + ">");
}
sb.append("key=");
sb.append(Constans.private_key);
String packageSign = null;
// 生成签名
packageSign = MD5.getMessageDigest(sb.toString().getBytes())
.toUpperCase();
sb2.append("<sign><![CDATA[");
sb2.append(packageSign);
sb2.append("]]></sign>");
sb2.append("</xml>");
// 这一步最关键 我们把字符转为 字节后,再使用“ISO8859-1”进行编码,得到“ISO8859-1”的字符串
try {
return new String(sb2.toString().getBytes(), "ISO8859-1");
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
4.请求数据,把得到的code_url生成二维码
[java] view
plaincopyprint?
/**
* 获得 code_url地址,生成二维码
* @author qiwenming
*/
class GetCodeUrl {
ProgressDialog dialog;
public void get() {
String url = Constans.url;
String entity = genProductArgs();
Log.d("URL", "url-----------:" + url);
Log.d(TAG, " entity----------: " + entity);
HttpUtils http = new HttpUtils();
RequestParams params = new RequestParams();
try {
params.setBodyEntity(new StringEntity(entity));
http.send(HttpMethod.POST, url, params,
new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> res) {
Log.i(TAG, res.result);
ResultXmlbean beanxml = Util.XmlToBean(res.result);
if (beanxml.getResult_code() == beanxml.getReturn_code()
&& beanxml.getResult_code().equals("SUCCESS")) {
//请求成功后,获得的code_url生成二维码
int QR_WIDTH = 300, QR_HEIGHT = 300;
//调用工具类生成二维码
Bitmap bitmap = ZxingUtils.createQRImage(beanxml.getCode_url(), QR_WIDTH,QR_HEIGHT);
Log.i(TAG, "####code_url## "+beanxml.getCode_url());
//设置二维码
iv_QRcode.setImageBitmap(bitmap);
} else {
Toast.makeText(getApplicationContext(),
"error", 0).show();
}
}
@Override
public void onFailure(HttpException arg0,
String arg1) {
Log.d(TAG, arg0.toString()+"--#####---"+arg1);
Log.d(TAG,"请求失败。。。。。。。。");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上已经解决了签名错误的问题,下面只是展示而已。
==================================================================
生成的二维码图片:
![](http://img.blog.csdn.net/20141214191515093?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl3ZW5taW5nc2hpd28=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
使用微信扫描的结果(微信中:发现--->扫一扫):
![](http://img.blog.csdn.net/20141214191729575?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWl3ZW5taW5nc2hpd28=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
代码下载
版权声明:本文为博主原创文章,未经博主允许不得转载。
plaincopyprint?
<span style="font-family: Arial, Helvetica, sans-serif; font-size: 18px; font-weight: bold; background-color: rgb(255, 255, 255);"> </span>
最近在做在做微信支付中的native支付第二种支付方式,在请求参数时遇到了最大的问题就是,body(商品描述)为中文时,签名失败,为英文时签名成功。这个问题搞了好几天,没有搞定,今天终于搞定了,特此分享一哈。
其实就是一句话的问题: 把我们生成的xml请求参数转为字节数组后,用“ISO8859-1”编码格式进行编码为字符串,就可以解决问题了。
[java] view
plaincopyprint?
return new String(sb2.toString().getBytes(), "ISO8859-1");
=============================================================================================================
上面的已经可以解决问题。下面我只是说说更详细的解决步骤。
1. 首先我们来看看官方的接口文档:
认证方式:HTTPS讣证,退款和冲正接口调用需要商户证书(证书在审核邮件附件
中)
请求采用POST方式
提交和返回结果采用XML格式
字符集默讣使用UTF-8,请勿使用其它字符集
商户不微信之间的交互(特别是Native回调和支付通知回调),都需要验证签名
4.1.统一支付接口
URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
统一支付接口,可接叐JSAPI/NATIVE/APP下预支付订单,返回预支付订单号。
NATIVE支付返回二维码code_url。
注意:JSAPI 下单前需要调用登录授权接口(详细调用说明请点击打开链接)获叏到用户
的Openid。
我们只需要传递对应的参数,请求“https://api.mch.weixin.qq.com/pay/unifiedorder ”,把得到“code_url”生成二维码即可。
2. 定义个常量类用来存储请求值
我定义了一常量类,保存我们用到的参数值(这只是我的Demo,不是真实中的项目,所以这么用,真实中不能这么弄,这个在真实中最好有服务器端操作,我们需要的只是一个"code_url"而已)。
[java] view
plaincopyprint?
/**
* 请求需要的参数
* @author Administrator
*
*/
public class Constans {
//appid
public static String APPID = "wxd930ea5d5a258f4f";
public static String auth_code = genNonceStr();
public static String body = "霸气的小明(qiwenming)";
public static String device_info = "1000";
public static String mch_id = "1900000109";
public static String nonce_str = genNonceStr();
public static String out_trade_no = genNonceStr();
public static String spbill_create_ip = "127.0.0.1";
public static String notify_url = "http://www.baidu.com";
public static String total_fee = "1";
public static String trade_type = "NATIVE";
public static String private_key = "8934e7d15453e97507ef794cf7b0519d";
public static String key = "L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K";
//请求地址
public static String url="https://api.mch.weixin.qq.com/pay/unifiedorder";
//生成随机字符串
private static String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
}
3.我们组织参数,生成请求参数(XML格式 )
这里分为2步:
第一步,我们把请求参数,按字典顺序存入到一个集合中;
第二步,我们把这些参数组装为xml格式的数据,并且完成签名的过程,这一步中最关键的是 我们要把生成的xml字符串,转为字节后,在使用“Isolates859-1”编码重新编码为字符串。
3.1按字典顺序存入到一个集合中:
[java] view
plaincopyprint?
<span style="font-size:18px;"><strong> </strong> </span><span style="font-size:14px;"> /**
* 把一个参数添加到 一个集合中,按字典顺序,这是为了后面生成 签名方便
*
* @return
*/
private String genProductArgs() {
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("appid", Constans.APPID));
packageParams.add(new BasicNameValuePair("appkey", Constans.key));
packageParams.add(new BasicNameValuePair("body", Constans.body));
packageParams.add(new BasicNameValuePair("input_charset", "UTF-8"));
packageParams.add(new BasicNameValuePair("mch_id", Constans.mch_id));
packageParams.add(new BasicNameValuePair("nonce_str",
Constans.nonce_str));
packageParams.add(new BasicNameValuePair("notify_url",
"http://www.baidu.com"));
packageParams.add(new BasicNameValuePair("out_trade_no",
Constans.out_trade_no));
packageParams.add(new BasicNameValuePair("spbill_create_ip",
Constans.spbill_create_ip));
packageParams.add(new BasicNameValuePair("total_fee", Constans.total_fee));
packageParams.add(new BasicNameValuePair("trade_type",
Constans.trade_type));
//调用genXml()方法获得xml格式的请求数据
return genXml(packageParams);
}</span><span style="font-size:18px;">
</span>
3.2生成XML格式参数,注意转码:
[java] view
plaincopyprint?
/**
* 生成xml格式的请求参数
*
* @param params
* 参数集合
* @return
*/
private String genXml(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
sb2.append("<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><xml>");
for (int i = 0; i < params.size(); i++) {
// sb是用来计算签名的
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
// sb2是用来做请求的xml参数
sb2.append("<" + params.get(i).getName() + ">");
sb2.append(params.get(i).getValue());
sb2.append("</" + params.get(i).getName() + ">");
}
sb.append("key=");
sb.append(Constans.private_key);
String packageSign = null;
// 生成签名
packageSign = MD5.getMessageDigest(sb.toString().getBytes())
.toUpperCase();
sb2.append("<sign><![CDATA[");
sb2.append(packageSign);
sb2.append("]]></sign>");
sb2.append("</xml>");
// 这一步最关键 我们把字符转为 字节后,再使用“ISO8859-1”进行编码,得到“ISO8859-1”的字符串
try {
return new String(sb2.toString().getBytes(), "ISO8859-1");
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
4.请求数据,把得到的code_url生成二维码
[java] view
plaincopyprint?
/**
* 获得 code_url地址,生成二维码
* @author qiwenming
*/
class GetCodeUrl {
ProgressDialog dialog;
public void get() {
String url = Constans.url;
String entity = genProductArgs();
Log.d("URL", "url-----------:" + url);
Log.d(TAG, " entity----------: " + entity);
HttpUtils http = new HttpUtils();
RequestParams params = new RequestParams();
try {
params.setBodyEntity(new StringEntity(entity));
http.send(HttpMethod.POST, url, params,
new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> res) {
Log.i(TAG, res.result);
ResultXmlbean beanxml = Util.XmlToBean(res.result);
if (beanxml.getResult_code() == beanxml.getReturn_code()
&& beanxml.getResult_code().equals("SUCCESS")) {
//请求成功后,获得的code_url生成二维码
int QR_WIDTH = 300, QR_HEIGHT = 300;
//调用工具类生成二维码
Bitmap bitmap = ZxingUtils.createQRImage(beanxml.getCode_url(), QR_WIDTH,QR_HEIGHT);
Log.i(TAG, "####code_url## "+beanxml.getCode_url());
//设置二维码
iv_QRcode.setImageBitmap(bitmap);
} else {
Toast.makeText(getApplicationContext(),
"error", 0).show();
}
}
@Override
public void onFailure(HttpException arg0,
String arg1) {
Log.d(TAG, arg0.toString()+"--#####---"+arg1);
Log.d(TAG,"请求失败。。。。。。。。");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上已经解决了签名错误的问题,下面只是展示而已。
==================================================================
生成的二维码图片:
使用微信扫描的结果(微信中:发现--->扫一扫):
代码下载
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- 高仿微信开源项目总结
- 微信开发者
- 微信上传图片
- 微信开发定时刷新accessToken
- C#的Xamarin开发小米盒子应用并以WCF实现微信通知
- 微信开发 java
- Xcode6集成微信SDK过程出错解决办法
- 微信背后的人性观
- iOS第三方支付-微信支付
- 微信java开发(nat123配制本地环境)
- inux关于readlink函数获取运行路径的小程序
- inux关于readlink函数获取运行路径的小程序
- 微信浏览器轮播图的使用经验
- 微信开放平台之公众号第三方平台开发及全网发布验证
- Android;Share SDK微信分享中遇到的问题以及解决方法
- 微信jssdk已无力吐槽
- 高仿微信实现左滑显示删除按钮功能
- 高仿微信本地图片选择器
- 微信公众号一键关注解决办法
- 微信支付(0923更新)商户支付密钥key的生成与设置