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)
}