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)

}

2.基于websockts协议

posted @ 2024-11-20 12:06  云岛夜川川  阅读(42)  评论(0)    收藏  举报