在这篇文章中,我们将带领您了解支付接口——WeChat/Alipay的全貌,包括微信支付宝官方支付接口的相关情况。同时,我们还将为您介绍有关AliPay、AlipayCrossborderWebsit
在这篇文章中,我们将带领您了解支付接口——WeChat / Alipay的全貌,包括微信支付宝官方支付接口的相关情况。同时,我们还将为您介绍有关AliPay、Alipay Cross border Website Payment for Opencart 2、Alipay Cross-border Magento Module V2.5 发布、alipay nodejs check ATN的知识,以帮助您更好地理解这个主题。
本文目录一览:- 支付接口——WeChat / Alipay(微信支付宝官方支付接口)
- AliPay
- Alipay Cross border Website Payment for Opencart 2
- Alipay Cross-border Magento Module V2.5 发布
- alipay nodejs check ATN
支付接口——WeChat / Alipay(微信支付宝官方支付接口)
1.微信支付
a.微信支付官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/index.html
b.在官网下载SDK
c.使用IDEA打开 java_sdk_v3.0.9,修改 WXPayConfig 类,将访问修饰符都改为 public
package com.github.wxpay.sdk;
import java.io.InputStream;
public abstract class WXPayConfig {
/**
* 获取 App ID
*
* @return App ID
*/
public abstract String getAppID();
/**
* 获取 Mch ID
*
* @return Mch ID
*/
public abstract String getMchID();
/**
* 获取 API 密钥
*
* @return API密钥
*/
public abstract String getKey();
/**
* 获取商户证书内容
*
* @return 商户证书内容
*/
public abstract InputStream getCertStream();
/**
* HTTP(S) 连接超时时间,单位毫秒
*
* @return
*/
public int getHttpConnectTimeoutMs() {
return 6*1000;
}
/**
* HTTP(S) 读数据超时时间,单位毫秒
*
* @return
*/
public int getHttpReadTimeoutMs() {
return 8*1000;
}
/**
* 获取WXPayDomain, 用于多域名容灾自动切换
* @return
*/
public abstract IWXPayDomain getWXPayDomain();
/**
* 是否自动上报。
* 若要关闭自动上报,子类中实现该函数返回 false 即可。
*
* @return
*/
public boolean shouldAutoReport() {
return true;
}
/**
* 进行健康上报的线程的数量
*
* @return
*/
public int getReportWorkerNum() {
return 6;
}
/**
* 健康上报缓存消息的最大数量。会有线程去独立上报
* 粗略计算:加入一条消息200B,10000消息占用空间 2000 KB,约为2MB,可以接受
*
* @return
*/
public int getReportQueueMaxSize() {
return 10000;
}
/**
* 批量上报,一次最多上报多个数据
*
* @return
*/
public int getReportBatchSize() {
return 10;
}
}
d.使用 maven 将项目 install 到本地仓库
e.pom文件中引入导入的SDK依赖
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>3.0.9</version>
</dependency>
f.新建 MyConfig 类继承 WXPayConfig
public class MyConfig extends WXPayConfig{
//公众账号ID
public static final String APP_ID = "";
//商户号
public static final String MCH_ID = "";
//API密钥
public static final String KEY = "";
//异步支付回调地址(外网)
public static final String NOTIFY_URL = "";
//异步退款回调地址(外网)
public static final String REFUND_NOTIFY_URL = "";
//---------------------------------------
private byte[] certData;
public MyConfig() throws Exception {
String certPath = "/path/to/apiclient_cert.p12";
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
public String getAppID() {
return APP_ID;
}
public String getMchID() {
return MCH_ID;
}
public String getKey() {
return KEY;
}
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
public IWXPayDomain getWXPayDomain() {
// 这个方法需要这样实现, 否则无法正常初始化WXPay
IWXPayDomain iwxPayDomain = new IWXPayDomain() {
public void report(String domain, long elapsedTimeMillis, Exception ex) {
}
public DomainInfo getDomain(WXPayConfig config) {
return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
return iwxPayDomain;
}
public int getHttpConnectTimeoutMs() {
return 8000;
}
public int getHttpReadTimeoutMs() {
return 10000;
}
}
g.统一下单、查询订单、退款
public class WechatUtil {
/**
* 统一下单(预支付)
* @param outTradeNo 外部订单号
* @param title 标题
* @param totalFee 总金额
* @param spbillCreateIp 客户端IP
* @return
* @throws Exception
*/
public static Map<String, String> prepay(String outTradeNo, String title, int totalFee, String spbillCreateIp) throws Exception {
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<String, String>();
data.put("body", title);
data.put("out_trade_no", outTradeNo);
data.put("fee_type", "CNY");
data.put("total_fee", String.valueOf(totalFee));
data.put("spbill_create_ip", spbillCreateIp);
data.put("notify_url", MyConfig.NOTIFY_URL);
data.put("trade_type", "NATIVE"); // 此处指定为扫码支付
data.put("product_id", "12"); //扫码支付时必传参数
Map<String, String> result = new HashMap<>();
try {
Map<String, String> resp = wxpay.unifiedOrder(data);
System.out.println(resp);
if("SUCCESS".equals(resp.get("return_code"))){
if("SUCCESS".equals(resp.get("result_code"))){
String prepay_id = resp.get("prepay_id");
String code_url = resp.get("code_url");
HashMap<String, String> signMap = new HashMap<String, String>();
signMap.put("appid", MyConfig.APP_ID);
signMap.put("partnerid", MyConfig.MCH_ID);
signMap.put("prepayid", prepay_id);
signMap.put("package", "Sign=WXPay");
signMap.put("noncestr", WXPayUtil.generateNonceStr());
signMap.put("timestamp", String.valueOf(System.currentTimeMillis()/1000));
String sign = WXPayUtil.generateSignature(signMap, MyConfig.KEY);
result.put("prepay_id", prepay_id);
result.put("code_url", code_url);
result.put("sign", sign);
result.putAll(signMap);
return result;
}else{
System.out.println(resp.get("err_code_des"));
}
}else{
System.out.println(resp.get("return_msg"));
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 查询订单
* @param outTradeNo 外部订单号
* @throws Exception
*/
public static void tradeQuery(String outTradeNo) throws Exception {
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", outTradeNo);
try {
Map<String, String> resp = wxpay.orderQuery(data);
System.out.println(resp);
if("SUCCESS".equals(resp.get("return_code"))){
if("SUCCESS".equals(resp.get("result_code"))){
//TODO 根据response中的结果继续业务逻辑处理
}else{
System.out.println(resp.get("err_code_des"));
}
}else{
System.out.println(resp.get("return_msg"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 退款
* @param outTradeNo 外部订单号
* @param outRefundNo 外部退款订单号
* @param totalFee 总金额
* @param refundFee 退款金额
* @throws Exception
*/
public static void refund(String outTradeNo, String outRefundNo, int totalFee, int refundFee) throws Exception {
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", outTradeNo);
data.put("out_trade_no", outTradeNo);
data.put("out_refund_no", outRefundNo);
data.put("total_fee", String.valueOf(totalFee));
data.put("refund_fee", String.valueOf(refundFee));
data.put("notify_url", MyConfig.REFUND_NOTIFY_URL);
try {
Map<String, String> resp = wxpay.refund(data);
System.out.println(resp);
if("SUCCESS".equals(resp.get("return_code"))){
if("SUCCESS".equals(resp.get("result_code"))){
//TODO 根据response中的结果继续业务逻辑处理
}else{
System.out.println(resp.get("err_code_des"));
}
}else{
System.out.println(resp.get("return_msg"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
h.支付/退款 回调
@RestController
public class WechatController {
@RequestMapping("/payment/wechatResult")
public String wechatResult(HttpServletRequest request){
try{
InputStream is = request.getInputStream();
//将InputStream转换成String
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
String resXml=sb.toString();
System.out.println(resXml);
//-------------------------------------------------------------------
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> notifyMap = WXPayUtil.xmlToMap(resXml); // 转换成map
if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
// 签名正确
// 进行处理。
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
String return_code = notifyMap.get("return_code");//状态
String out_trade_no = notifyMap.get("out_trade_no");//订单号
if (out_trade_no == null) {
return "";
}
//TODO 根据notifyMap中的结果继续业务逻辑处理
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml> ";
}
}catch (Exception e){
e.printStackTrace();
}
return "";
}
@RequestMapping("/payment/wechatRefundResult")
public String wechatRefundResult(HttpServletRequest request){
try {
BufferedReader reader = request.getReader();
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
String resXml=sb.toString();
System.out.println(resXml);
//---------------------------------------------------
Map<String, String> notifyMap = WXPayUtil.xmlToMap(resXml);
if ("SUCCESS".equals(notifyMap.get("return_code"))) {
String req_info = notifyMap.get("req_info");
/**
* 解密方式
* 解密步骤如下:
* (1)对加密串A做base64解码,得到加密串B
* (2)对商户key做md5,得到32位小写key* ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )
* (3)用key*对加密串B做AES-256-ECB解密(PKCS7Padding)
*/
byte[] byteArray = (new BASE64Decoder()).decodeBuffer(req_info);
String key = DigestUtils.md5Hex(MyConfig.KEY.getBytes("UTF-8"));
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
String resultStr = new String(cipher.doFinal(byteArray));
Map<String, String> aesMap = WXPayUtil.xmlToMap(resultStr);
//TODO 根据aesMap中的结果继续业务逻辑处理
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml> ";
}
}catch (Exception e){
e.printStackTrace();
}
return "";
}
}
2.支付宝支付
a.官方文档地址:https://docs.open.alipay.com/204/105297/
b.在pom文件中引入SDK依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.7.89.ALL</version>
</dependency>
c.统一下单、交易查询、交易退款
public class AlipayUtil {
//HTTPS请求地址
public static final String URL = "https://openapi.alipay.com/gateway.do";
//异步回调地址(外网)
public static final String NOTIFY_URL = "";
//应用ID
public static final String APP_ID = "";
//应用私钥
public static final String APP_PRIVATE_KEY = "";
//支付宝公钥
public static final String ALIPAY_PUBLIC_KEY = "";
//编码格式
public static final String CHARSET = "utf-8";
/**
* 生成APP支付订单信息
* @param outTradeNo 外部订单号
* @param title 标题
* @param totalAmount 总金额
* @return
*/
public static String getOrderStr(String outTradeNo,String title,String totalAmount){
//实例化客户端
AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject(title);
model.setOutTradeNo(outTradeNo);
model.setTotalAmount(totalAmount);
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl(NOTIFY_URL);
try {
//这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if(response.isSuccess()){
String orderStr = response.getBody();//就是orderString 可以直接给客户端请求,无需再做处理。
System.out.println(orderStr);
return orderStr;
}else{
System.out.println(response.getSubCode());
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
/**
* 交易查询
* @param outTradeNo 外部订单号
*/
public static void tradeQuery(String outTradeNo){
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2"); //获得初始化的AlipayClient
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();//创建API对应的request类
request.setBizContent("{" +
" \"out_trade_no\":\"" + outTradeNo + "\"," +
" }");//设置业务参数
try {
AlipayTradeQueryResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类
if(response.isSuccess()){
System.out.print(response.getBody());
//TODO 根据response中的结果继续业务逻辑处理
}else{
System.out.println(response.getSubCode());
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
}
/**
* 交易退款
* @param outTradeNo 外部订单号
* @param refundAmount 退款金额
*/
public static void tradeRefund(String outTradeNo, String refundAmount){
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2"); //获得初始化的AlipayClient
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();//创建API对应的request类
request.setBizContent("{" +
" \"out_trade_no\":\"" + outTradeNo + "\"," +
" \"refund_amount\":\"" + refundAmount + "\"" +
" }");//设置业务参数
try {
AlipayTradeRefundResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类
if(response.isSuccess()){
System.out.print(response.getBody());
//TODO 根据response中的结果继续业务逻辑处理
}else{
System.out.println(response.getSubCode());
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
}
}
d.支付回调
@RestController
public class AlipayController {
@RequestMapping("/payment/alipayResult")
public String alipayResult(HttpServletRequest request){
//获取支付宝POST过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
try {
boolean flag = AlipaySignature.rsaCheckV1(params, AlipayUtil.ALIPAY_PUBLIC_KEY, AlipayUtil.CHARSET,"RSA2");
if(flag){
//TODO 根据params中的结果继续业务逻辑处理
return "success";
}else{
return "failure";
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return "failure";
}
}
AliPay
AliPay
- 阿里的支付也就是支付宝,官网已经出了Python的SDK了,所以先下载:pip3 install alipay-sdk-python 网址
- 支付宝沙箱环境的地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info
一、使用详情:
第1步:访问沙箱环境地址,注册一个商家账户点击
- 密钥生成方式1(推荐):生成RSA密钥
- 密钥生成方式2:OpenSSL工具生成密钥
- 按照上面方式生成商户的公钥和私钥,把公钥放入网站私钥自己留着签名用,设置应用公钥后
- 下面是商户信息以及卖家信息下载一个支付宝的沙箱环境
- 然后按照下面的账号和密码登录和支付,只支持安卓
第2步:阅读文档 找到一个适合自己的API 点击
- 这里选择:统一收单下单并支付页面接口 点击
- 仔细阅读文档按照文档的参数要求去向接口发请求
第3步:代码实例
- 回调url的测试要放在公网IP上,所以测试的时候放入自己服务器.
- alipay-sdk-python
from django.conf.urls import url
from django.contrib import admin
from app01.views import AliPayView, PayHandlerView
urlpatterns = [
url(r''^admin/'', admin.site.urls),
url(r''^pay$'', AliPayView.as_view()),
url(r''^alipay_handler'', PayHandlerView.as_view()),
]
from django.shortcuts import render, redirect
from django.http import HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.domain.AlipayTradePrecreateModel import AlipayTradePrecreateModel
from alipay.aop.api.request. AlipayTradePrecreateRequest import AlipayTradePrecreateRequest
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest
import time
# Create your views here.
# 沙箱环境地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info
# "https://openapi.alipaydev.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2"
def ali_pay():
# 为阿里支付实例化一个配置信息对象
alipay_config = AlipayClientConfig(sandbox_debug=True)
# 初始化各种配置信息
# 阿里提供服务的接口
alipay_config.server_url = "https://openapi.alipaydev.com/gateway.do"
# 申请的沙箱环境的app_id
alipay_config.app_id = "2016091800540924"
# 商户的私钥
with open("keys/app_private_key.txt") as f:
alipay_config.app_private_key = f.read()
# 阿里的公钥
with open("keys/alipay_public_key.txt") as f:
alipay_config.alipay_public_key = f.read()
# 实例化一个支付对象并返回
alipay_client = DefaultAlipayClient(alipay_client_config=alipay_config)
return alipay_client
class AliPayView(APIView):
def get(self, request):
return render(request, "pay.html")
# 生成支付宝自带页面的API
def post(self, request):
# 得到阿里支付的实例化对象
client = ali_pay()
# 为API生成一个模板对象 初始化参数用的
model = AlipayTradePagePayModel()
# 订单号
model.out_trade_no = "pay" + str(time.time())
# 金额
model.total_amount = 8888
# 商品标题
model.subject = "测试"
# 商品详细内容
model.body = "支付宝测试"
# 销售产品码,与支付宝签约的产品码名称
model.product_code = "FAST_INSTANT_TRADE_PAY"
# 实例化一个请求对象
request = AlipayTradePagePayRequest(biz_model=model)
# get请求 用户支付成功后返回的页面请求地址
request.return_url = "http://140.143.63.45:8000/alipay_handler"
# post请求 用户支付成功通知商户的请求地址
request.notify_url = "http://140.143.63.45:8000/alipay_handler"
# 利用阿里支付对象发一个获得页面的请求 参数是request
response = client.page_execute(request, http_method="GET")
return redirect(response)
class PayHandlerView(APIView):
def get(self, request):
# return_url的回调地址
print(request.data)
# 用户支付成功之后回到哪
return HttpResponse("return_url测试")
def post(self, request):
print(request.data)
# 用户支付成功 在这里修改订单状态以及优惠券贝里等等情况
return HttpResponse("notify_url")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
{# <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>#}
</head>
<body>
<form method="POST">
{% csrf_token %}
<input type="text" name="money">
<input type="submit" value="去支付" />
</form>
</body>
</html>
二、旧版
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from base64 import decodebytes, encodebytes
import json
class AliPay(object):
"""
支付宝支付接口(PC端支付接口)
"""
def __init__(self, appid, app_notify_url, app_private_key_path,
alipay_public_key_path, return_url, debug=False):
self.appid = appid
self.app_notify_url = app_notify_url
self.app_private_key_path = app_private_key_path
self.app_private_key = None
self.return_url = return_url
with open(self.app_private_key_path) as fp:
self.app_private_key = RSA.importKey(fp.read())
self.alipay_public_key_path = alipay_public_key_path
with open(self.alipay_public_key_path) as fp:
self.alipay_public_key = RSA.importKey(fp.read())
if debug is True:
self.__gateway = "https://openapi.alipaydev.com/gateway.do"
else:
self.__gateway = "https://openapi.alipay.com/gateway.do"
def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
biz_content = {
"subject": subject,
"out_trade_no": out_trade_no,
"total_amount": total_amount,
"product_code": "FAST_INSTANT_TRADE_PAY",
# "qr_pay_mode":4
}
biz_content.update(kwargs)
data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
return self.sign_data(data)
def build_body(self, method, biz_content, return_url=None):
data = {
"app_id": self.appid,
"method": method,
"charset": "utf-8",
"sign_type": "RSA2",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0",
"biz_content": biz_content
}
if return_url is not None:
data["notify_url"] = self.app_notify_url
data["return_url"] = self.return_url
return data
def sign_data(self, data):
data.pop("sign", None)
# 排序后的字符串
unsigned_items = self.ordered_data(data)
unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
sign = self.sign(unsigned_string.encode("utf-8"))
# ordered_items = self.ordered_data(data)
quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)
# 获得最终的订单信息字符串
signed_string = quoted_string + "&sign=" + quote_plus(sign)
return signed_string
def ordered_data(self, data):
complex_keys = []
for key, value in data.items():
if isinstance(value, dict):
complex_keys.append(key)
# 将字典类型的数据dump出来
for key in complex_keys:
data[key] = json.dumps(data[key], separators=('','', '':''))
return sorted([(k, v) for k, v in data.items()])
def sign(self, unsigned_string):
# 开始计算签名
key = self.app_private_key
signer = PKCS1_v1_5.new(key)
signature = signer.sign(SHA256.new(unsigned_string))
# base64 编码,转换为unicode表示并移除回车
sign = encodebytes(signature).decode("utf8").replace("\n", "")
return sign
def _verify(self, raw_content, signature):
# 开始计算签名
key = self.alipay_public_key
signer = PKCS1_v1_5.new(key)
digest = SHA256.new()
digest.update(raw_content.encode("utf8"))
if signer.verify(digest, decodebytes(signature.encode("utf8"))):
return True
return False
def verify(self, data, signature):
if "sign_type" in data:
sign_type = data.pop("sign_type")
# 排序后的字符串
unsigned_items = self.ordered_data(data)
message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
return self._verify(message, signature)
from django.shortcuts import render,redirect,HttpResponse
from django.views.decorators.csrf import csrf_exempt
from utils.pay import AliPay
import time
from django.conf import settings
#依赖:pip3 install pycryptodome
def aliPay():
obj = AliPay(
appid=settings.APPID,
app_notify_url=settings.NOTIFY_URL, # 如果支付成功,支付宝会向这个地址发送POST请求(校验是否支付已经完成)
return_url=settings.RETURN_URL, # 如果支付成功,重定向回到你的网站的地址。
alipay_public_key_path=settings.PUB_KEY_PATH, # 支付宝公钥
app_private_key_path=settings.PRI_KEY_PATH, # 应用私钥
debug=True, # 默认False,
)
return obj
def index(request):
if request.method == ''GET'':
return render(request,''index.html'')
alipay = aliPay()
# 对购买的数据进行加密
money = float(request.POST.get(''price''))
out_trade_no = "x2" + str(time.time())
# 1. 在数据库创建一条数据:状态(待支付)
query_params = alipay.direct_pay(
subject="刘亦菲", # 商品简单描述
out_trade_no= out_trade_no, # 商户订单号
total_amount=money, # 交易金额(单位: 元 保留俩位小数)
)
pay_url = "https://openapi.alipaydev.com/gateway.do?{}".format(query_params)
return redirect(pay_url)
def pay_result(request):
"""
支付完成后,跳转回的地址
:param request:
:return:
"""
params = request.GET.dict()
sign = params.pop(''sign'', None)
alipay = aliPay()
status = alipay.verify(params, sign)
if status:
return HttpResponse(''支付成功'')
return HttpResponse(''支付失败'')
@csrf_exempt
def update_order(request):
"""
支付成功后,支付宝向该地址发送的POST请求(用于修改订单状态)
:param request:
:return:
"""
if request.method == ''POST'':
from urllib.parse import parse_qs
body_str = request.body.decode(''utf-8'')
post_data = parse_qs(body_str)
post_dict = {}
for k, v in post_data.items():
post_dict[k] = v[0]
alipay = aliPay()
sign = post_dict.pop(''sign'', None)
status = alipay.verify(post_dict, sign)
if status:
# 修改订单状态
out_trade_no = post_dict.get(''out_trade_no'')
print(out_trade_no)
# 2. 根据订单号将数据库中的数据进行更新
return HttpResponse(''支付成功'')
else:
return HttpResponse(''支付失败'')
return HttpResponse('''')
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r''^admin/'', admin.site.urls),
url(r''^index/'', views.index),
url(r''^pay_result/'', views.pay_result),
url(r''^update_order/'', views.update_order),
]
ALLOWED_HOSTS = ["*",]
# 支付相关配置
APPID = "2016082500309412"
NOTIFY_URL = "http://1.1.1.1:80/update_order/"
RETURN_URL = "http://1.1.1.1:80/pay_result/"
PRI_KEY_PATH = "keys/app_private_2048.txt"
PUB_KEY_PATH = "keys/alipay_public_2048.txt"
Alipay Cross border Website Payment for Opencart 2
经过近一周辛苦的编码、调试、实际支付测试, Alipay境外支付插件的Opencart版本发布了!支持Opencart 2.0及以上版本。市场上虽然之前已经有了类似的支付模块,但发现多少都存在以下问题:
1,没有结算货币设置功能(结算货币是商户和支付宝协商的收款币种),虽然不设置结算货币,大多时候也可以支付,但不符合支付宝接口文档规范。
2,没有人民币"直传"功能,人民币直传指当客户订单货币为RMB(CNY)时,无需汇率转换,直接传递人民币金额到支付宝网关。
3,支付宝消息通知功能缺失,如遇网络故障,或者客户支付后没有跳转回商户网站,可能会导致漏单或者订单状态不同步问题。
4,没有支付日志功能,Log功能是记录支付过程中,支付插件和支付宝服务器通讯过程中的消息数据,当支付出现问题时候,可以查看日志信息,来快速查明原因。
由此,决定开发出一系列完善的Opencart支付宝模块。先来看看Alipay Cross-border Webstie Payment Extension for Opencart 2.x支付模块。
Opencart支付方式选择界面,采用最新的蓝色支付宝Logo图片
提交订单后,就跳转来到了支付宝收银台,支付宝采用国际即时汇率,自动将订单金额换算成人民币。Alipay Cross-border Payment属于即时到账交易。支付宝最近优化了收银台页面,重点突出手机钱包扫一扫支付,手机扫码后,输入支付宝支付密码,成功后就跳转回商户网站了。也可以点击右侧【登陆账户付款】,然后输入支付宝账户和密码登陆后支付。
我们的Opencart Cross-border Website Payment支付模块实现了支付宝异步通知功能,如果用户支付后,立即关闭了浏览器,或者突然网络中断、抑或是突然断电关机,没有按照正常逻辑跳转回商户网站,这时候,订单也会生成,同时订单状态也会正确更新为已付款!
Opencart网站支付成功页面。
Opencart网站管理员后台,订单列表,可以看到支付成功订单状态为: Proccessing
Opencart网站管理员后台,Order History界面,订单备注中包含有alipay notify字样,表示该订单是收到支付宝消息通知时建立的。正常情况下,在用户支付后跳转回网站前,支付宝消息通知已经领先一步到达商户网站所在服务器了。我们的支付插件,接收到通知消息后,就赶紧保存订单,并更新支付状态。
Opencart Cross-border Website Payment Extension参数设置界面。Settlement Currency是支付宝结算给商户的货币。Order Status是客户支付成功后的订单状态。Log功能是记录支付过程中,支付插件和支付宝服务器通讯过程中的消息数据,当支付出现问题时候,可以查看日志信息,来快速查明原因。
Alipay Cross-border Magento Module V2.5 发布
收到客户邮件询问,支付方式为Alipay Cross-border Website Payment, 为什么支付成功后,在Alipay后台订单列表中的订单号后面多出了一些数字,如下图所示:
原因是在V2.5新版本中,增加了订单号冲突解决机制。
如果客户有两个以上Magento站点,使用同一个Alipay支付账户,那么订单号就很有可能重复,在支付的时候,Alipay就会报错。
因此呢,Alipay Cross-border Payment支付模块,在Magento标准的订单号后面,增加了4位随机数字,就近乎100%避免了这个问题的发生。当然了,如果你只有一个Magento站点,或者是各个Magento站点采用不同的订单号前缀,不会发生订单号重复问题,可以在支付模块中禁用该选项,这样提交到Alipay的订单号就不会带奇怪的随机数字了。
Perfect Alipay Extension!
alipay nodejs check ATN
请问有人用nodejs 来 接入 alipay么? 我今天尝试的时候 ,在 notify的时候,check ATN,请求到服务器的时候,一直
{ [Error: getaddrinfo ENOTFOUND] code: ''ENOTFOUND'', errno: ''ENOTFOUND'', syscall: ''getaddrinfo'' }
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
var partner = AlipayConfig.partner;
var veryfy_path = AlipayConfig.HTTPS_VERIFY_PATH + "partner=" + partner + "¬ify_id=" + params["notify_id"];
requestUrl(AlipayConfig.ALIPAY_HOST,veryfy_path,function(responseTxt){
if(responseTxt){
callback(true);
}else{
callback(false);
}
});
今天关于支付接口——WeChat / Alipay和微信支付宝官方支付接口的分享就到这里,希望大家有所收获,若想了解更多关于AliPay、Alipay Cross border Website Payment for Opencart 2、Alipay Cross-border Magento Module V2.5 发布、alipay nodejs check ATN等相关知识,可以在本站进行查询。
本文标签: