结合gin框架在沙箱环境下实现电脑网站支付和当面支付

文章目录

  • 配置支付宝开放平台
  • 编写代码
  • 测试
    • 电脑网站支付
    • 当面扫码支付

配置支付宝开放平台

支付宝开放平台

点击链接,扫码进入后,点击沙箱:
image-20240617095226161

点击沙箱应用,可以看到APPID,接口加签方式选择系统默认密钥就行,启用公钥模式。然后点击查看。

image-20240617095759799

由于后端使用go,我们选择非JAVA语言,这里我们只需要应用公钥和支付宝公钥。

image-20240617100250709

接下来我们在项目根目录新建配置文件config.yaml

AppId: 你的AppId
PrivateKey: 你的应用私钥
AliPublicKey: 你的支付宝公钥
NotifyURL: http://182.254.140.235:8080/notify
ReturnURL: http://182.254.140.235:8080/callback

分别将你的AppIdPrivateKeyAliPublicKey复制进去。其中NotifyURL是的异步通知地址,这个地址需要是公网地址,这样支付宝才可以访问然后给你发支付后的通知,ReturnURL是回调地址,用户在网站上支付成功后会跳转进入的界面,这个地址不要求公网地址,如果是在本机测试,写http://127.0.0.1:8080/callback即可。

编写代码

在项目根目录新建main.go文件 :

package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/skip2/go-qrcode"
	"github.com/smartwalle/alipay/v3"
	"github.com/spf13/viper"
)

var (
	cfg    Config
	client *alipay.Client
)

// Config 定义配置结构体
type Config struct {
	AppId        string `mapstructure:"AppId"`
	PrivateKey   string `mapstructure:"PrivateKey"`
	AliPublicKey string `mapstructure:"AliPublicKey"`
	NotifyURL    string `mapstructure:"NotifyURL"`
	ReturnURL    string `mapstructure:"ReturnURL"`
}

// 初始化函数,用于读取配置文件和初始化支付宝客户端
func init() {
	v := viper.New()
	v.SetConfigFile("config.yaml")
	if err := v.ReadInConfig(); err != nil {
		panic(err)
	}
	if err := v.Unmarshal(&cfg); err != nil {
		panic(err)
	}
	client, _ = alipay.New(cfg.AppId, cfg.PrivateKey, false)
	if err := client.LoadAliPayPublicKey(cfg.AliPublicKey); err != nil {
		panic(err)
	}
}

func main() {
	r := gin.Default()
	r.GET("/sitePay", SitePay)
	r.GET("/facePay", FacePay)
	r.POST("/notify", Notify)
	r.GET("/callback", Callback)
	srv := &http.Server{
		Addr:    fmt.Sprintf(":%d", 8080),
		Handler: r,
	}
	go func() {
		log.Println("服务器启动成功!")
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			panic(err)
		}
	}()

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	log.Println("服务器正在关闭...")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		panic(err)
	}
	log.Println("服务器已关闭.")
}

// SitePay 电脑网站支付
func SitePay(c *gin.Context) {
	pay := alipay.TradePagePay{ // 电脑网站支付
		Trade: alipay.Trade{
			Subject:     "测试订单balabala",                       // 订单主题
			OutTradeNo:  fmt.Sprintf("%d", time.Now().Unix()), // 商户订单号,必须唯一
			TotalAmount: "100.00",                             // 订单金额
			ProductCode: "FAST_INSTANT_TRADE_PAY",             // 电脑网站支付,产品码为固定值
			NotifyURL:   cfg.NotifyURL,                        // 异步通知地址
			ReturnURL:   cfg.ReturnURL,                        // 回调地址
		},
	}
	url, err := client.TradePagePay(pay) // 生成支付链接
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  err.Error(),
		})
	}
	c.Redirect(http.StatusTemporaryRedirect, url.String()) // 重定向到支付宝支付页面
}

// FacePay 扫码支付
func FacePay(c *gin.Context) {
	pay := alipay.TradePreCreate{ // 扫码支付
		Trade: alipay.Trade{
			Subject:     "测试订单balabala",                       // 订单主题
			OutTradeNo:  fmt.Sprintf("%d", time.Now().Unix()), // 商户订单号,必须唯一
			TotalAmount: "100.00",                             // 订单金额
			ProductCode: "FACE_TO_FACE_PAYMENT",               // 当面付,产品码为固定值
			NotifyURL:   cfg.NotifyURL,                        // 异步通知地址
		},
	}
	resp, err := client.TradePreCreate(c, pay) // 生成支付二维码
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  err.Error(),
		})
	}
	qrCode, err := qrcode.New(resp.QRCode, qrcode.Medium)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  err.Error(),
		})
	}

	// 设置二维码的大小
	qrCode.DisableBorder = true
	png, err := qrCode.PNG(256) // 生成256x256的PNG图片
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate QR code image"})
		return
	}

	// 返回PNG图像
	c.Data(http.StatusOK, "image/png", png)
}

// Callback Callback函数,处理支付结果
func Callback(c *gin.Context) {
	_ = c.Request.ParseForm()
	err := client.VerifySign(c.Request.Form)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  err.Error(),
		})
		return
	}
	_, err = c.Writer.Write([]byte("<h1>成功支付的界面,可由商家自由定制</h1>"))
	if err != nil {
		panic(err)
	}
}

// Notify Notify函数,处理支付宝的异步通知
func Notify(c *gin.Context) {
	_ = c.Request.ParseForm()
	// 业务逻辑处理,比如更新订单状态,由开发者自由定制
	fmt.Println(c.Request.Form.Get("trade_no"))
	fmt.Println(c.Request.Form.Get("out_trade_no"))
	fmt.Println(c.Request.Form.Get("total_amount"))
	fmt.Println(c.Request.Form.Get("subject"))
	fmt.Println(c.Request.Form.Get("trade_status"))
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "ok",
	})
}

运行代码前记得go mod tidy一下。

测试

我选择在公网服务器上测试,这样便于接收支付宝发来的异步通知。没有公网服务器可以使用内网穿透工具。

运行程序:go run main.go

image-20240617101843713

电脑网站支付

输入网址http://182.254.140.235:8080/sitePay会自动跳转到支付宝支付页面:

20240617-102308

接下来在沙箱账号中获取买家账号、登录密码、支付密码。

image-20240617102633081

输入买家账号和密码(扫码支付不可用,用沙箱工具扫码也不行)。

image-20240617102726548

输入支付密码后,如果支付成功,就会自动跳转到之前设置的回调地址。

20240617103226_rec_

在终端也可以看到我们的异步通知路由和回调路由都成功的被调用,电脑网址支付测试完成。

image-20240617103521016

当面扫码支付

在沙箱工具处下载支付宝沙箱版:

image-20240617103707021

在手机上打开安装好的app用之前的买家账号和登录密码登录!!!

接着在浏览器中访问:http://182.254.140.235:8080/facePay,会自动显示支付二维码:

image-20240617103901372

在手机上使用沙箱版支付宝扫一扫,支付成功后页面不会调转,当面支付是这样的,所以在代码中也没有设置回调地址。

在终端处可以看到异步通知路由被访问了,当面支付功能测试成功。

image-20240617104056992

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/715999.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C的I/O操作

目录 引言 一、文件与目录操作 1. 打开与关闭文件 2. 文件读写操作 3. 文件定位与错误处理 二、字符流与字节流 1. 字符流处理 2. 字节流处理 三、序列化与反序列化 1. 序列化 2. 反序列化 四、新的I/O&#xff08;NIO&#xff09; 表格总结 文件与目录操作 字符…

nuxt3+vue3+vite+TS实现国际化

前言 博主最近打算用Nuxt3重构了自己SSR博客&#xff0c;打算添加国际化功能&#xff0c;众所周知&#xff0c;实现国际化已是一个很常见的功能。用户可以根据自己的喜好&#xff0c;设置页面的自己合适的语言&#xff0c;从而实现国际化浏览。这样用户体验度会大大提升。博客…

使用Midjourney为产品创建出色效果图-关键词

使用MJ为产品创建效果图并不难&#xff0c;可以使用这个固定提示词公式。 Mockup empty, blank [ product ], [ decorating items ] [ background or context ], [ 1- 3 descriptive style], [ color palette ] 创建产品形象 首先&#xff0c;你需要准备一个透明背景的产品。…

Python中文自然语言处理(NLP)中文分词工具库之pkuseg使用详解

概要 在中文自然语言处理(NLP)中,分词是一个基础且关键的任务。pkuseg 是由北京大学开发的一个中文分词工具,专为处理现代汉语而设计。它采用了先进的深度学习技术,能够准确地进行中文分词,同时支持自定义词典和多领域分词。本文将详细介绍 pkuseg 库,包括其安装方法、…

动态 SQL

动态 SQL 是 MyBatis 的强大特性之一&#xff0c;能够完成不同条件下不同的 sql 拼接。也就是说执行的 SQL 语句并不是固定的&#xff0c;而是不同人的不同操作执行的语句会有所差异。MyBatis 通过使用 标签 的方式来实现这种灵活性的。 <if>标签 例如在有一些网站进行…

一些个人电脑用的小工具软件

1 个人电脑信息管理 如下&#xff1b; 整理自己的电脑信息&#xff1b;录入&#xff0c;保存&#xff0c;查询&#xff1b;添加和更新界面如下&#xff0c; 每次添加、更新之后重新点一下菜单的浏览&#xff1b; 下载&#xff0c; https://download.csdn.net/download/bcb…

如何使用 pip 卸载所有已安装的 Python 包?

在开发过程中&#xff0c;我们可能会安装许多 Python 包&#xff0c;有时需要彻底清理环境&#xff0c;以便从头开始或者解决冲突问题。下面将介绍如何使用 pip 命令卸载所有已安装的 Python 包。 一、列出所有已安装的包 首先&#xff0c;需要列出当前环境中所有已安装的包。…

Vue49-props属性

一、当同一个组件标签被使用多次 因为data属性写的是函数形式&#xff01; 二、需求&#xff1a;老王也想用<Student>组件&#xff0c;但是需要动态把老王想要的值传进来。 2-1、使用props属性接收参数 使用props属性&#xff0c;接收的这三个参数&#xff0c;是被保存在…

入门机器视觉的正确打开方式——徒手撸一个python+opencv实现的机器视觉简易调试工具(上)

目录 1.引言2.框架思路3.环境搭建4.图像处理流程化的实现5.流水线上的算法块5.1 算法块的可视化 6.总结7.调试工具成品链接PS.扩展阅读ps1.六自由度机器人相关文章资源ps2.四轴机器相关文章资源ps3.移动小车相关文章资源 1.引言 在当今AI时代&#xff0c;关于视觉识别似乎已被…

位运算算法:编程世界中的魔法符号

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一. 常见位运算总结 二、常见位运算题目 2.1 位1的个数 2.2 比特数记位&#xff08;典型dp&#xff09; 2.3 汉明距离 2.4 只出现一次的数字&#xff08;1&#xff09; 2.5 只出…

QtScrcpy最出色的C++开源手机投屏控制软件

QtScrcpy是一款开源的跨平台屏幕录制和投屏工具 基本概述&#xff1a; 它基于Android的ADB&#xff08;Android Debug Bridge&#xff09;和Electron框架&#xff0c;为用户提供了简洁且功能强大的用户界面。 支持平台&#xff1a; QtScrcpy支持Windows、macOS和Linux三大…

算力与能源正在成为世界的硬通货,看超级计算机安腾如何突围

特斯拉创始人马斯克公开表态称未来两年人工智能行业将由“缺硅”变为“缺电”。据媒体报道&#xff0c;OpenAI的ChatGPT每天消耗超过50万千瓦时的电力&#xff0c;用于处理约2亿个用户请求&#xff0c;相当于美国家庭每天用电量的1.7万多倍。除了这类生成式AI耗能外&#xff0c…

【Linux】使用 iptables 验证访问HDFS 所使用到的端口

目录 ​编辑 一、实操背景 二、iptables 简介 三、模拟操作 一、实操背景 背景&#xff1a; 在客户有外网的服务器需要访问内网大数据集群HDFS&#xff0c;使用iptable模拟测试需要开放的端口。 二、iptables 简介 具体介绍看文章&#xff1a; 【Linux】Iptables 详解与实战…

Elasticsearch出现Connection reset by peer

Elasticsearch出现Connection reset by peer分析 1.异常&#xff1a; 2024-06-13 13:17:10.539 WARN [http-nio-30411-exec-9]com.longdaotech.config.ESConfig -onFailure node:[hosthttp://192.168.239.253:9200] 2024/6/13 13:17:10 2024-06-13 13:17:10.541 WARN [http-n…

aop注解快速实现数据脱敏返回

说明&#xff1a; 公司之前数据接口数据管理不严格&#xff0c;很多接口的敏感数据都没有脱敏处理&#xff0c;直接返回给前端了&#xff0c;然后被甲方的第三方安全漏洞扫出来&#xff0c;老板要求紧急处理&#xff0c;常用的话在单个字段上加上脱敏注解会更加的灵活&#xf…

Win11升级24H2出现绿屏怎么办?这些方法帮你解决!

在Win11电脑操作中&#xff0c;用户为了体验24H2版本推出的新功能&#xff0c;所以要把系统版本升级为24H2版本。但升级过程中电脑却出现了绿屏问题&#xff0c;不清楚要怎么操作才能解决绿屏的问题&#xff1f;接下来小编给大家分享几种简单有效的解决方法&#xff0c;让大家能…

轨迹优化 | 图解欧氏距离场与梯度场算法(附ROS C++/Python实现)

目录 0 专栏介绍1 什么是距离场&#xff1f;2 欧氏距离场计算原理3 双线性插值与欧式梯度场4 仿真实现4.1 ROS C实现4.2 Python实现 0 专栏介绍 &#x1f525;课程设计、毕业设计、创新竞赛、学术研究必备&#xff01;本专栏涉及更高阶的运动规划算法实战&#xff1a;曲线生成…

基于Java和SSM框架的多人命题系统

你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果你对多人命题系统感兴趣或者有相关开发需求&#xff0c;文末可以找到我的联系方式。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java SSM框架 工具&#xff1a;Eclipse、MySQL Workbench、…

大众点评_token,mtgsig

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未经许可禁止转载&#xff0…