微信统一下单支付中关于Body不支持中文编码的解决方法

因工作需要对接微信的扫码支付,这里用到的统一下单支付接口。开始一切正常。可是当传递参数body为中文的时候,返回错误提示:body不是utf8编码。看字面意思是编码不是utf-8,经常做java的朋友都对这类问题见怪不怪了(心中早有了解决方法),可是这次没有想像的那么简单,试过了N种方法,结果要么是:签名不对,要么是:body不是utf8编码。看来这次没有那么简单,毕竟要对接人家的接口,所幸到网上搜索一下,遇到此问题的还真不少,照着别人的解决方法也不好使,所有方法都不行的情况下,只好回头来耐心研究了。还好费了点工夫总算解决,下面说一下解决的方法吧。保证切实可用!

首先有说对中文进行unicode编码,结果试了是不可以的,见下图:

微信统一下单支付中关于Body不支持中文编码的解决方法_第1张图片

 

再就是有说进行urlencode编码,试了结果也是不行的:

微信统一下单支付中关于Body不支持中文编码的解决方法_第2张图片

 

下面分析一下提单环节用到中文编码的几个地方:

1、xml的内容中中文要使用utf-8

2、对参数签名的加密方法无论用MD5还是SHA256,均需要指定utf-8

3、数据post到签名下单接口时要指定utf-8编码

4、读取微信返回参数时使用utf-8编码(虽然这个不影响业务逻辑,不过指定好可以正确获取微信的中文信息)

然后针对上面的每个环节看一下我的代码:

一、构造map

HashMap map=new HashMap();

String body=RequestUtil.getSafeStr(request, "body");

map.put("appid",wxBean.getAppId());//公众账号id

map.put("mch_id",wxBean.getMchId());//商户号

map.put("sub_mch_id", sub_mch_id);//子商户号

map.put("nonce_str",timestamp);//随机字符串

map.put("sign_type","HMAC-SHA256");//签名方式

map.put("body",body);//商品描述

map.put("out_trade_no", tradeno);//商户订单号

map.put("total_fee",pay_money+"");//总金额 分

map.put("spbill_create_ip",uip);//终端ip

map.put("notify_url", SiteUrl+"/mch/notify.jsp");//通知地址

map.put("trade_type", "NATIVE");//交易类型

map.put("product_id", "1");//商品id 否 native必传

String xml=WxUtil.covertToXml(map,wxBean.getMchKey(),"HMACSHA256");

二、生成加签名的xml字符串

public static String covertToXml(Map m,String key,String signtype){

StringBuffer sb=new StringBuffer();

String sign = "";

try{

sign=generateSignature(m, key,signtype);

}catch(Exception e){

e.printStackTrace();

}

sb.append("");

Iterator it = m.keySet().iterator();

String kname;

while(it.hasNext()) {

kname= (String)it.next();

sb.append("<"+kname+">").append(m.get(kname)).append("");

}

sb.append("").append(sign).append("");

sb.append("");

return sb.toString();

}

三、对应的加签方法(支持MD5或SHA256)

public static String generateSignature(final Map data, String key, String signType) throws Exception {

Set keySet = data.keySet();

String[] keyArray = keySet.toArray(new String[keySet.size()]);

Arrays.sort(keyArray);

StringBuilder sb = new StringBuilder();

for (String k : keyArray) {

if (k.equals("sign")) {

continue;

}

if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名

sb.append(k).append("=").append(data.get(k).trim()).append("&");

}

sb.append("key=").append(key);

if ("MD5".equals(signType)) {

return MD5(sb.toString()).toUpperCase();

}

else if ("HMACSHA256".equals(signType)) {

return HMACSHA256(sb.toString(), key);

}

else {

throw new Exception(String.format("Invalid sign_type: %s", signType));

}

}

//MD5加密

public static String MD5(String str) {

MessageDigest messageDigest = null;

try {

messageDigest = MessageDigest.getInstance("MD5");

messageDigest.reset();

messageDigest.update(str.getBytes("UTF-8"));

} catch (NoSuchAlgorithmException e) {

System.out.println("NoSuchAlgorithmException caught!");

System.exit(-1);

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

byte[] byteArray = messageDigest.digest();

StringBuffer md5StrBuff = new StringBuffer();

for (int i = 0; i < byteArray.length; i++) {

if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {

md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));

} else {

md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));

}

}

return md5StrBuff.toString();

}

/**

* 生成 HMACSHA256

* @param data 待处理数据

* @param key 密钥

* @return 加密结果

* @throws Exception

*/

public static String HMACSHA256(String data, String key) throws Exception {

Mac sha256_HMAC = Mac.getInstance("HmacSHA256");

SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");

sha256_HMAC.init(secret_key);

byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));

StringBuilder sb = new StringBuilder();

for (byte item : array) {

sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));

}

return sb.toString().toUpperCase();

}

四、将以上三步生成好的XML字符串提交到微信统一下单接口即可

String ret=WxUtil.requestXml("https://api.mch.weixin.qq.com/pay/unifiedorder", xml);

然后贴一下requestXml方法的详细代码:

public static String requestXml(String url,String data){

BasicHttpClientConnectionManager connManager;

connManager = new BasicHttpClientConnectionManager(

RegistryBuilder.create()

.register("http", PlainConnectionSocketFactory.getSocketFactory())

.register("https", SSLConnectionSocketFactory.getSocketFactory())

.build(),

null,

null,

null

);

String rets="";

HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connManager).build();

HttpPost httpPost = new HttpPost(url);

RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(30000).setConnectTimeout(30000).build();

httpPost.setConfig(requestConfig);

StringEntity postEntity = new StringEntity(data, "UTF-8");

httpPost.addHeader("Content-Type", "text/xml");

httpPost.setEntity(postEntity);

HttpResponse httpResponse = null;

try{

httpResponse=httpClient.execute(httpPost);

HttpEntity httpEntity = httpResponse.getEntity();

rets=EntityUtils.toString(httpEntity, "UTF-8");

}catch(Exception e){

e.printStackTrace();

}

return rets;

}

经过以上步骤即可成功解决BODY中文UTF-8编码的问题,最后效果图如下:

微信统一下单支付中关于Body不支持中文编码的解决方法_第3张图片

 

最后,在找解决方法的时候,偶然发现个人也可以申请微信支付接口,原来一直以为只有企业才可以,服务商叫"易快得",经过在官网注册(域名是中文名的全拼)后发现从申请到微信审核通过只用了10分钟 就成功了,需要的朋友可以了解下。

你可能感兴趣的:(java,jsp)