微信app支付 签名错误 以及 访问https 的解决办法 Required credentials not available for BASIC <any...

请尊重知识,请尊重原创 更多资料参考请见  http://www.cezuwang.com/listFilm?page=1&areaId=906&filmTypeId=1

 

微信app支付 签名错误 以及 访问https 的解决办法
微信支付的接口不同于支付宝等其他第三方接口足够友好,所以这里有必要对 微信签名错误和访问https接口做一些小结以供参考。


签名错误:
  首先总结原因,可能发生签名错误的原因如下:
1 密钥错误,密钥是32位长的一串字符,类似于 f0fnf5872825aien55end044e092le39 ,如果需要重新设置 ,位置在 设置位置:账户设置-安全设置-API安全
2 本地签名程序
    基本遵照微信官方文档说明即可
https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=4_3
传递哪些参数 需要根据文档说明 https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_1

参考(内部的一些关键参数只提供参考,位数不对):
sb  字符串   appid=wx5382e5300d7f6e555f&body=Corsair Neutron Series GTX 480GB 固态硬盘&mch_id=1237315833041&nonce_str=1B72746255EF01F9D75400995C62EA12
&notify_url=http://m.dahongwa.com/pay/notify&out_trade_no
=151023113401857821&spbill_create_ip=10.244.1.171&total_fee=84462&trade_type=APP&key=f0fn3f5872825ai4en55end044e092le39

再对此字符串进行md5加密之后调成大写,即为sign签名

生成的xml文档:

<xml>
		<appid>wx5382e5300d7f6e555f</appid>
		<body><![CDATA[Corsair Neutron Series GTX 480GB 固态硬盘]]></body>
		<mch_id>1237315833041</mch_id>
		<nonce_str>1B72746255EF01F9D75400995C62EA12</nonce_str>
		<notify_url>http://m.dahongwa.com/pay/notify</notify_url>
		<out_trade_no>151023113401857821</out_trade_no>
		<sign><![CDATA[CD0DCCA447A6C0B0482C4D43A545A0BA]]></sign>
		<spbill_create_ip>10.244.1.171</spbill_create_ip>
		<total_fee>84462</total_fee>
		<trade_type>APP</trade_type>
	</xml>


生成的xml是提交给 微信的参数,必须和签名的字符串里的值相同
如果返回的微信参数提示 签名错误,可以到微信官方测试测试地址测试
https://pay.weixin.qq.com/wiki/tools/signverify/
微信返回信息中,如果出现签名错误,可以把自己的资料填写在上面的测试用例中获取微信生成的签名,
如果测试sign与自己生成的不同 返回上步检查,如果微信生成的和自己生成的签名相同,但是微信还是返回签名错误,则一定是商品中文(body)编码。
有几个地方的编码必须注意.
设置 sb  字符串 的时候 body一定为utf-8,sb字符串md5加密的时候 必须为utf-8,
传递给 微信的时候 ,此参数也必须为 utf-8 :entity = new StringEntity(xml,"utf-8");

httpclient 头部和参数 也设置成utf-8:
	httpPost.setEntity(entity);
    httpPost.addHeader("Content-Type", "text/html;charset=UTF-8");  
	httpClient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");
	httpPost.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); 


这几个编码优先级逐步提高,也就是说后面的会覆盖前面的。

  请尊重知识,请尊重原创 更多资料参考请见  http://www.cezuwang.com/listFilm?page=1&areaId=906&filmTypeId=1
由于微信的接口是https,在生产环境又只能通过代理访问,所以通常的http接口访问会返回错误信息:

WARN,http-apr-9002-exec-4,10-22 20:21:30.393,httpclient.HttpMethodDirector.authenticateHost:288 - Required credentials not available for BASIC <any realm>@api.mch.weixin.qq.com:443
WARN,http-apr-9002-exec-4,10-22 20:21:30.393,httpclient.HttpMethodDirector.authenticateHost:290 - Preemptive authentication requested but no default credentials available
INFO,http-apr-9002-exec-4,10-22 20:21:30.583,httpclient.HttpMethodDirector.executeWithRetry:439 - I/O exception (java.net.ConnectException) caught when processing request: Connection refused
INFO,http-apr-9002-exec-4,10-22 20:21:30.583,httpclient.HttpMethodDirector.executeWithRetry:445 - Retrying request
INFO,http-apr-9002-exec-4,10-22 20:21:30.591,httpclient.HttpMethodDirector.executeWithRetry:439 - I/O exception (java.net.ConnectException) caught when processing request: Connection refused
INFO,http-apr-9002-exec-4,10-22 20:21:30.592,httpclient.HttpMethodDirector.executeWithRetry:445 - Retrying request
INFO,http-apr-9002-exec-4,10-22 20:21:30.594,httpclient.HttpMethodDirector.executeWithRetry:439 - I/O exception (java.net.ConnectException) caught when processing request: Connection refused
INFO,http-apr-9002-exec-4,10-22 20:21:30.595,httpclient.HttpMethodDirector.executeWithRetry:445 - Retrying request
java.net.ConnectException: Connection refused
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:579)
	at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:618)
	at com.legendshop.model.app.wxpay.MySSLProtocolSocketFactory.createSocket(MySSLProtocolSocketFactory.java:92)
	at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)


这是因为代理访问被微信拒绝,所以需要重新设置访问程序:

StringEntity entity;
		HttpResponse httpResponse;
		int proxyPortCon = 0;
		DefaultHttpClient httpClient = new DefaultHttpClient(); //创建默认的httpClient实例
		try {	
			entity = new StringEntity(xml,"utf-8");
			
			if("true".equalsIgnoreCase(useProxy) ){
				
			    X509TrustManager xtm = new X509TrustManager(){  //创建TrustManager
			    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
			    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
			    public X509Certificate[] getAcceptedIssuers() { return null; }
			    };
			    
			    X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
		            public boolean verify(String arg0, SSLSession arg1) {
		                return true;
		            }
		            public void verify(String arg0, SSLSocket arg1) throws IOException {}
		            public void verify(String arg0, String[] arg1, String[] arg2) throws SSLException {}
		            public void verify(String arg0, X509Certificate arg1) throws SSLException {}
		        };
			    
			    //TLS1.0与SSL3.0基本上没有太大的差别,可粗略理解为TLS是SSL的继承者,但它们使用的是相同的SSLContext
	            SSLContext ctx = SSLContext.getInstance("TLS");
	            //使用TrustManager来初始化该上下文,TrustManager只是被SSL的Socket所使用
	            ctx.init(null, new TrustManager[] { xtm }, null);
	            //创建SSLSocketFactory
	            SSLSocketFactory socketFactory = new SSLSocketFactory(ctx);
	            socketFactory.setHostnameVerifier(hostnameVerifier);
	            //通过SchemeRegistry将SSLSocketFactory注册到我们的HttpClient上
	            httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", socketFactory, 443));
	            
			    proxyPortCon = Integer.parseInt(proxyPort);
			    
			    HttpHost proxy = new HttpHost(proxyHost, proxyPortCon);
			    httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
			    
			}
			    HttpPost httpPost = new HttpPost(unifiedorder);  //创建HttpPost
			    httpPost.setEntity(entity);
			    httpPost.addHeader("Content-Type", "text/html;charset=UTF-8");  
			    httpClient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); 
			    //httpPost.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");  
			    httpResponse = httpClient.execute(httpPost); //执行POST请求
			    if (AppUtils.isNotBlank(httpResponse)) {
				HttpEntity httpEntity = httpResponse.getEntity();
				String result = EntityUtils.toString(httpEntity, "UTF-8");
				
				}

  


下面贴一些代码 供参考:


app前段调用微信统一下单接口

/**
	 * 微信支付统一下单接口
	 * @param orderInfoJson 请求参数json 
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	@RequestMapping(value = "/pay/unifiedorder", method =RequestMethod.POST)
	@ResponseBody
	public  Result getOrderInfo(HttpServletRequest request, HttpServletResponse response,@RequestParam("code") String code, @RequestParam("orderInfoJson") String orderInfoJson) throws UnsupportedEncodingException {
		Result result = null;
		//日志记录
		AppServiceLog.info("orderInfoJson is {}", orderInfoJson);
		AppServiceLog.visit(AppInterfaceEnum.WECHAT_PAY, "/pay/unifiedorder", getUserName(request));
		
		Map<?, ?> paramMap=JsonToMap.getBody(orderInfoJson);
		final Gson gson =new Gson();
		
		WXPrepayVO orderInfo = gson.fromJson(gson.toJson(paramMap),WXPrepayVO.class);
		
		WXPrepay prePay = new WXPrepay();
		
		//获取订单信息
		result = orderService.payUnifiedorder(request,orderInfo,prePay);
		
		return result;
		
	}



服务器构造对象 向微信服务器发起https访问,以获取预支付id

public Result payUnifiedorder(HttpServletRequest request,WXPrepayVO orderInfo,WXPrepay prePay) throws UnsupportedEncodingException {
		
		Result result = new Result();
		Double totalAmount = new Double(0);
		
		OrderTemp orderTemp = orderTempDao.getOrderByOrderNum(orderInfo.getOut_trade_no());
		Order order = null;
		
		if(AppUtils.isBlank(orderTemp)){
			order = orderDao.getOrderByOrderNumLimitOne(orderInfo.getOut_trade_no());
			if(AppUtils.isNotBlank(order)){
				totalAmount = order.getTotalAmount();
			}
		}else{
			totalAmount = orderTemp.getTotalAmount();
		}
		
		if(AppUtils.isBlank(orderTemp) && AppUtils.isBlank(order)){
			result.setCode(ReturnCode.orderIsNotExist.value());
			result.setMessage(ReturnCode.orderIsNotExist.desc());
			return result;
		}
		
		//商品描述
		String bodyStr = Base64Decoder.Decoder(orderInfo.getBody());
		
		String spbill_create_ip = request.getRemoteAddr();
		
		prePay.setAppid(appId);
		prePay.setBody(bodyStr);
		prePay.setPartnerKey(appKey);
		prePay.setMch_id(mchId);
		prePay.setNotify_url(notifyUrl);
		prePay.setOut_trade_no(orderInfo.getOut_trade_no());
		prePay.setSpbill_create_ip(spbill_create_ip);
		
		DecimalFormat df = new DecimalFormat("#");
		prePay.setTotal_fee(df.format(totalAmount * 10 * 10));
		//prePay.setTotal_fee("1");
		prePay.setTrade_type(PayTypeEnum.WX_APP_PAY.value());
		
		//代理
		String useProxyConfig = PropertiesUtil.getUseProxy();
		String proxyHostConfig = PropertiesUtil.getProxyHost();
		String proxyPortConfig = PropertiesUtil.getProxyPort();
		
        //此处添加获取openid的方法,获取预支付订单需要此参数!!!!!!!!!!! 
		// 获取预支付订单号
		WePayResponse wePayResponse = prePay.submitXmlGetPrepayId(useProxyConfig,proxyHostConfig,proxyPortConfig);
		wePayResponse.setPartnerId(mchId);
		wePayResponse.setPackageS("Sign=WXPay");
		wePayResponse.setNonceStr(OrderUtil.CreateNoncestr());
		wePayResponse.setTimeStamp(new Date().getTime());
		
		if(wePayResponse.getResultCode().equals("SUCCESS")){
			result.setCode(ReturnCode.OK.value());
			result.setMessage(wePayResponse.getReturnMsg());
			result.setSuccess(true);
		}else{
			result.setMessage(wePayResponse.getErrCodeDes());
		}
		
		result.setObject(wePayResponse);
		return result;
	}



/**
	 * 生成预支付订单
	 * 
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	@SuppressWarnings("deprecation")
	public WePayResponse submitXmlGetPrepayId(String useProxy,String proxyHost,String proxyPort) throws UnsupportedEncodingException {
		
		System.out.println(useProxy +"--"+ proxyHost +"---"+ proxyPort);
		String xml = getPackage();
		WePayResponse response = null;
		StringEntity entity;
		HttpResponse httpResponse;
		int proxyPortCon = 0;
		DefaultHttpClient httpClient = new DefaultHttpClient(); //创建默认的httpClient实例
		try {	
			entity = new StringEntity(xml,"utf-8");
			
			if("true".equalsIgnoreCase(useProxy) ){
			
/**
下面这段代码 用来处理访问https的请求
**/	
			    X509TrustManager xtm = new X509TrustManager(){  //创建TrustManager
			    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
			    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
			    public X509Certificate[] getAcceptedIssuers() { return null; }
			    };
			    
			    X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
		            public boolean verify(String arg0, SSLSession arg1) {
		                return true;
		            }
		            public void verify(String arg0, SSLSocket arg1) throws IOException {}
		            public void verify(String arg0, String[] arg1, String[] arg2) throws SSLException {}
		            public void verify(String arg0, X509Certificate arg1) throws SSLException {}
		        };
			    
			    //TLS1.0与SSL3.0基本上没有太大的差别,可粗略理解为TLS是SSL的继承者,但它们使用的是相同的SSLContext
	            SSLContext ctx = SSLContext.getInstance("TLS");
	            //使用TrustManager来初始化该上下文,TrustManager只是被SSL的Socket所使用
	            ctx.init(null, new TrustManager[] { xtm }, null);
	            //创建SSLSocketFactory
	            SSLSocketFactory socketFactory = new SSLSocketFactory(ctx);
	            socketFactory.setHostnameVerifier(hostnameVerifier);
	            //通过SchemeRegistry将SSLSocketFactory注册到我们的HttpClient上
	            httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", socketFactory, 443));
	            
/****
下面这段代码 使用代理访问https外部接口

****/
			    proxyPortCon = Integer.parseInt(proxyPort);
			    
			    HttpHost proxy = new HttpHost(proxyHost, proxyPortCon);
			    httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
			    
			}
			    HttpPost httpPost = new HttpPost(unifiedorder);  //创建HttpPost
			    httpPost.setEntity(entity);
			    httpPost.addHeader("Content-Type", "text/html;charset=UTF-8");  
			    httpClient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8"); 
			    //httpPost.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");  
			    httpResponse = httpClient.execute(httpPost); //执行POST请求
			    
						if (AppUtils.isNotBlank(httpResponse)) {
				HttpEntity httpEntity = httpResponse.getEntity();
				String result = EntityUtils.toString(httpEntity, "UTF-8");
				// 过滤
				result = result.replaceAll("<![CDATA[|]]>", "");
				String prepay_id = Jsoup.parse(result).select("prepay_id").html();
				String trade_type = Jsoup.parse(result).select("trade_type").html();
				String returnCode =  Jsoup.parse(result).select("return_code").html();
				String returnMsg =  Jsoup.parse(result).select("return_msg").html();
				
				String resultCode = Jsoup.parse(result).select("result_code").html();
				String errCode =  Jsoup.parse(result).select("err_code").html();
				String errCodeDes =  Jsoup.parse(result).select("err_code_des").html();
				
				response = WePayResponse.newInstance();
				response.setPrepayId(prepay_id);
				response.setTradeType(trade_type);
				response.setReturnCode(returnCode);
				response.setReturnMsg(returnMsg);
				
				response.setResultCode(resultCode);
				response.setErrCode(errCode);
				response.setErrCodeDes(errCodeDes);
				
				if (response != null)
					return response;
			}
			// 释放资源
		} catch (Exception e) {
			e.printStackTrace();
		}
		return response;
	}







 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

annan211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值