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. 生成二维码tokentoken, err := generate_token()if err != nil {return "", err}//2.使用redis存储tokenerr = redis.QRsign(token)//3. 调用第三方 API生成二维码并返回Urlsign_url, err = generateQr_url(token)return
}
func VerifyToken(token string) error {//验证tokenreturn 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/" + tokenfmt.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 redisimport ("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. 生成二维码tokentoken, err := generate_token()if err != nil {return nil, err}//2.使用redis存储tokenerr = redis.QRsign(token)//3.使用qrcode的encoding方法return qrcode.Encode("http://127.0.0.1:8080/api/v1/qr/"+token, qrcode.Medium, 256)}