java微信退款时很多人会遇到抛出一个异常 unexpected end of file from server
相信很多人都会遇到这个问题,因为只要你做过微信支付然后再来做退款的时候就会习惯性地把支付的源码直接拿过来用,然后开始退款的时候就报错了~
问题的原因在于:支付的时候,你是把钱给微信,那么怎么简单怎么弄,现在你要拿出来,那得做点什么了~
支付不需要证书,但退款需要SSL证书!
ok,开始去微信商户平台(https://pay.weixin.qq.com/index.php/core/cert/api_cert)
在API安全中招下载证书点击下载证书,java服务端应该用这个 apiclient_cert.p12的证书,他需要几个jar包~ 分别是httpclient-4.3.4.jar,httpcore-4.3.2.jar,这里附上这几个jar包的下载地址顺便:https://download.csdn.net/user/wjj1996825/uploads
然后就是关键代码了,普通的可能就是直接打开Http地址就好了,带上证书,你得这么操作;
第一步:先封装一个带有ssl客户端请求的工具类:
package com.atap.utils.wxpayutil;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.atap.wxpay.Constants;
/**
* This example demonstrates how to create secure connections with a custom SSL
* context.
*/
public class ClientCustomSSL {
public static String doRefund(String url,String data) throws Exception {
/**
* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
*/
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File(Constants.WXSSL_STRING_PAHT));//P12文件在服务器磁盘中的目录
try {
/**
* 此处要改成你的MCHID
* */
keyStore.load(instream, Constants.MCHID.toCharArray());//这里写密码..默认是你的MCHID
} finally {
instream.close();
}
// Trust own CA and all self-signed certs
/**
* 此处要改成你的MCHID
* */
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, Constants.MCHID.toCharArray())//这里也是写密码的
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
HttpPost httpost = new HttpPost(url); // 设置响应头信息
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(data, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
try {
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
EntityUtils.consume(entity);
return jsonStr;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
}
说明:1、修改你 证书的地址(按照微信开发文档需要点击安装一下,放到一个具有管理员权限的位置,并且不能被下载到,避免被恶意操作)
2、修改 两处密码,一般填你们公司的mch_id
第二步:调用这个ssl客户端请求工具类:
String xmlInfo = "<xml>"
+ "<appid>" + WX_APPID + "</appid>"
+ "<mch_id>" + MCHID + "</mch_id>"
+ "<nonce_str>" + nonceStr+ "</nonce_str>"
+ "<sign>" + sign + "</sign>"
+"<out_trade_no>" + orderSn + "</out_trade_no>"
+"<out_refund_no>" + orderSn + "</out_refund_no>"
+ "<total_fee>" + (int) relAmount + "" + "</total_fee>"
+ "<refund_fee>" + (int) relAmount + "" + "</refund_fee>"
+ "<notify_url>"+ WX_PAY_CALLBACK+ "</notify_url>"
+ "</xml>";
// 请求
String response = ClientCustomSSL.doRefund(wxUrl, xmlInfo).toString();
// 处理请求结果
Map<String, Object> resultMap = new HashMap<String, Object>();
resultMap = WxPaySignatureUtils.getMapFromXML(response);// 解析返回值
if ("SUCCESS".equals(resultMap.get("return_code").toString())
&& "SUCCESS".equals(resultMap.get("result_code").toString())) {
System.out.println("微信退单请求成功");
// 在订单数据库表中更新该条订单记录
} else {
if (resultMap != null&& "SUCCESS".equals(resultMap.get("return_code").toString())) {
// 通信接口二级错误
System.out.println("微信退单请求错误,通信接口二级错误:" + "result_code"
+ resultMap.get("result_code") + "err_code"
+ resultMap.get("err_code") + "result_msg"
+ resultMap.get("err_code_des"));
} else {
// 通信接口一级错误
System.out.println("result_code=="+ resultMap.get("return_code").toString());
}
}
// 之前做微信支付的时候是这样调用发送请求
String response= WXHttpUtil.doPostString(xmlInfo, wxUrl);
// 现在做微信退款时换成这样调用发送请求
String response= ClientCustomSSL.doRefund(wxUrl, xmlInfo).toString();
这样就可以成功的进行微信支付退款操作了!