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

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

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

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

 

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

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

 

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

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

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

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

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

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

一、构造map

HashMap map=new HashMap<String, String>();

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<String,String> m,String key,String signtype){

StringBuffer sb=new StringBuffer();

String sign = "";

try{

sign=generateSignature(m, key,signtype);

}catch(Exception e){

e.printStackTrace();

}

sb.append("<xml>");

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

String kname;

while(it.hasNext()) {

kname= (String)it.next();

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

}

sb.append("<sign>").append(sign).append("</sign>");

sb.append("</xml>");

return sb.toString();

}

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

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

Set<String> 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.<ConnectionSocketFactory>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不支持中文编码的解决方法

 

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

发布了52 篇原创文章 · 获赞 71 · 访问量 41万+
展开阅读全文

Java开发支付宝接口(报文报不是UTF-8编码的错误)

02-24

package com.spasvo.main; import com.csii.pp.key.KeyProvider; import com.csii.pp.signature.XMLSignature; import com.csii.pp.transport.HttpClientTransport; import java.net.URL; public class AlipayTest { private XMLSignature xs = new com.csii.pp.signature.XMLSignature(); private static String contentType = "application/xml; charset=utf-8"; private static String encoding = "UTF-8"; //签名 public String sign(String xmlString, String sigNode) throws Exception{ byte[] signature = xs.sign(xmlString.getBytes("UTF-8"), "Message", sigNode, kp.getPrivateKey("bkt0452010061201", "111111")); return new String(signature, "UTF-8"); } // public void send(String urlString,String xmlString,String reqId){ public void send(){ String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Cartoon><Message id=\"249f9d82-b7e4-4608-b0bb-0cb0ba973aa1\"><CSVReq id=\"CSVReq\"><version>3.0.0</version><instId>ALIPAY</instId><certId>ALIPAY2007072500</certId><date>20140610 10:21:52</date><accountName>王洪章</accountName><bankCardNo>6217524512001000319</bankCardNo><bankCardType>D</bankCardType><certificateType>1</certificateType><certificateNo>230102194410242416</certificateNo><mobilePhone>13502513211</mobilePhone></CSVReq></Message></Cartoon>"; String reqId = "CSVReq"; String urlString = "http://130.1.9.222:9082/paygate/alipay"; try{ HttpClientTransport httpClientTransport = new HttpClientTransport(); String body=sign(xmlString, reqId); StringBuffer message = new StringBuffer(messageHead); message.append(body); String all = message.toString(); System.out.println("请求报文:"+all); URL url = new URL(urlString); httpClientTransport.setProtocol(url.getProtocol()); httpClientTransport.setHost(url.getHost()); httpClientTransport.setPort(url.getPort() == -1 ? url.getDefaultPort() : url.getPort()); httpClientTransport.setTarget(url.getPath()); httpClientTransport.setQueryString(url.getQuery()); httpClientTransport.setContentType(contentType); httpClientTransport.submit(all.getBytes()); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) { AlipayTest a = new AlipayTest(); try { a.send(); // a.send(url,xmlString,reqId); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 这个是测试的程序,可以成功发送和接受报文,但是用项目调用这个方法发送报文的时候,给我们返回的报文报我们发送的报文不是UTF-8编码的报文。我的项目的编码是UTF-8的编码,类的编码也是UTF-8的编码, 求大神指教一下这是什么原因。 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览