go实现QR订阅的几种方法
1.基于HTTP协议
1.1返回图片地址
通过qrcode生成二维码图片到static目录下,然后返回二维码图片的地址,返回的地址可以使用base64加密也可以直接返回。
controller层
func QrSignHandler(c *gin.Context) {
qr_url, err := logic.Generate_Qr()
if err != nil {
c.JSON(10005, err)
return
}
c.JSON(200, gin.H{
"qrCodeUrl": "/"+qr_url, //返回绝对路径
})
}
//DosignHandler 验证扫码的签到
func DosignHandler(c *gin.Context) {
// 获取参数
token:=c.Param("token")
// 验证token是否存在
if err:=logic.VerifyToken(token);err!=nil {
c.JSON(502,gin.H{
"msg": err.Error(),
})
}else {
c.JSON(200,gin.H{"msg":"签到成功"})
}
}
logic层
func Generate_Qr() (sign_url string, err error) {
//1. 生成二维码token
token, err := generate_token()
if err != nil {
return "", err
}
//2.使用redis存储token
err = redis.QRsign(token)
//3. 调用第三方 API生成二维码并返回Url
sign_url, err = generateQr_url(token)
return
}
func VerifyToken(token string) error {
//验证token
return redis.VerifyQrToken(token)
}
func generate_token() (string, error) {
b := make([]byte, 32)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), nil
}
// generateQr_url 生成qr
func generateQr_url(token string) (string, error) {
//生成内容
Qr_content := "http://127.0.0.1:8080/api/v1/qr/" + token
fmt.Println("签到:",Qr_content)
//二维码保存位置
qr_root := "static/qrcodes/"
qr_file_path := qr_root + token + ".png"
defer delfile(qr_root,qr_file_path)
// 创建二维码并保存
err := qrcode.WriteFile(Qr_content, qrcode.Medium, 256, qr_file_path)
if err != nil {
zap.L().Error("创建二维码失败!", zap.Error(err))
return "", err
}
return qr_file_path, nil
}
// delfile 删除多余的二维码
func delfile(dir string,newqr string) {
err:= filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
if err!=nil {
return err
}
if !info.IsDir(){
if filepath.Clean(path) != filepath.Clean(newqr) {
zap.L().Info("我要删除二维码了!",zap.Any("遍历的path:",path),zap.Any("新生成的tokenqr:",newqr))
return os.Remove(path)
}
}
return nil
})
if err!=nil {
zap.L().Error("删除二维码失败!",zap.Error(err))
return
}
}
dao层
package redis
import (
"context"
"errors"
"time"
"github.com/go-redis/redis/v8"
)
func QRsign(token string) error {
err := Rdb.Set(context.Background(), "Sign_Token", token, 10*time.Second).Err()
if err != nil {
return err
}
return nil
}
func VerifyQrToken(token string) error {
//验证token是否存在和是否过期
result, err := Rdb.Get(context.Background(), "Sign_Token").Result()
if err != nil {
if err == redis.Nil {
return errors.New("二维码已过期")
}
return err
}
if result != token {
return errors.New("二维码不存在")
}
return nil
}
1.2 返回图片的base64内容
由于1.1的方法需要在服务器生成二维码图片,导致会消耗服务器资源。尽管已经采用了及时删除图片策略,但交互还是繁琐
使用qrcode.Encode把二维码图片内容编码成byte类型的数据,再传给前端,前端直接使用img标签就可以解码,当然需要将byte进行base64编码再返回。
controller层
// QrsignBybyteHandler 通过二维码的字节内容返回
func QrsignBybyteHandler(c *gin.Context) {
data_byte, err := logic.Generate_Qr_By_byte()
if err != nil {
zap.L().Error("Generate_Qr_By_byte err:", zap.Error(err))
return
}
base64data := base64.RawStdEncoding.EncodeToString(data_byte)
c.JSON(200, gin.H{"data": base64data})
}
logic层
func Generate_Qr_By_byte() ([]byte, error) {
//1. 生成二维码token
token, err := generate_token()
if err != nil {
return nil, err
}
//2.使用redis存储token
err = redis.QRsign(token)
//3.使用qrcode的encoding方法
return qrcode.Encode("http://127.0.0.1:8080/api/v1/qr/"+token, qrcode.Medium, 256)
}

浙公网安备 33010602011771号