diff --git a/api/api.go b/api/api.go index 6649789..846fa99 100644 --- a/api/api.go +++ b/api/api.go @@ -5,14 +5,16 @@ import ( "schisandra-cloud-album/api/oauth_api" "schisandra-cloud-album/api/sms_api" "schisandra-cloud-album/api/user_api" + "schisandra-cloud-album/api/websocket_api" ) // Apis 统一导出的api type Apis struct { - UserApi user_api.UserAPI - CaptchaApi captcha_api.CaptchaAPI - SmsApi sms_api.SmsAPI - OAuthApi oauth_api.OAuthAPI + UserApi user_api.UserAPI + CaptchaApi captcha_api.CaptchaAPI + SmsApi sms_api.SmsAPI + OAuthApi oauth_api.OAuthAPI + WebsocketApi websocket_api.WebsocketAPI } // Api new函数实例化,实例化完成后会返回结构体地指针类型 diff --git a/api/oauth_api/oauth_api.go b/api/oauth_api/oauth_api.go index 162d0da..8d96d6b 100644 --- a/api/oauth_api/oauth_api.go +++ b/api/oauth_api/oauth_api.go @@ -16,6 +16,7 @@ import ( "github.com/yitter/idgenerator-go/idgen" "gorm.io/gorm" "schisandra-cloud-album/api/user_api/dto" + "schisandra-cloud-album/api/websocket_api" "schisandra-cloud-album/common/constant" "schisandra-cloud-album/common/enum" "schisandra-cloud-album/common/redis" @@ -44,6 +45,11 @@ var roleService = service.Service.RoleService // @Router /api/oauth/generate_client_id [get] func (OAuthAPI) GenerateClientId(c *gin.Context) { ip := c.ClientIP() + clientId := redis.Get(constant.UserLoginClientRedisKey + ip).Val() + if clientId != "" { + result.OkWithData(clientId, c) + return + } v1 := uuid.NewV1() redis.Set(constant.UserLoginClientRedisKey+ip, v1.String(), 0) result.OkWithData(v1.String(), c) @@ -74,9 +80,9 @@ func (OAuthAPI) CallbackNotify(c *gin.Context) { key := strings.TrimPrefix(msg.EventKey, "qrscene_") res := wechatLoginHandler(msg.FromUserName, key) if !res { - return messages.NewText("登录失败") + return messages.NewText(ginI18n.MustGetMessage(c, "LoginFailed")) } - return messages.NewText("登录成功") + return messages.NewText(ginI18n.MustGetMessage(c, "LoginSuccess")) case models.CALLBACK_EVENT_UNSUBSCRIBE: msg := models.EventUnSubscribe{} @@ -97,9 +103,9 @@ func (OAuthAPI) CallbackNotify(c *gin.Context) { } res := wechatLoginHandler(msg.FromUserName, msg.EventKey) if !res { - return messages.NewText("登录失败") + return messages.NewText(ginI18n.MustGetMessage(c, "LoginFailed")) } - return messages.NewText("登录成功") + return messages.NewText(ginI18n.MustGetMessage(c, "LoginSuccess")) } @@ -147,11 +153,12 @@ func (OAuthAPI) CallbackVerify(c *gin.Context) { // @Router /api/oauth/get_temp_qrcode [get] func (OAuthAPI) GetTempQrCode(c *gin.Context) { clientId := c.Query("client_id") + ip := c.ClientIP() if clientId == "" { result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) return } - qrcode := redis.Get(constant.UserLoginQrcodeRedisKey + clientId).Val() + qrcode := redis.Get(constant.UserLoginQrcodeRedisKey + ip + ":" + clientId).Val() if qrcode != "" { data := response.ResponseQRCodeCreate{} @@ -172,7 +179,7 @@ func (OAuthAPI) GetTempQrCode(c *gin.Context) { result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c) return } - wrong := redis.Set(constant.UserLoginQrcodeRedisKey+clientId, serializedData, time.Hour*24*30).Err() + wrong := redis.Set(constant.UserLoginQrcodeRedisKey+ip+":"+clientId, serializedData, time.Hour*24*30).Err() if wrong != nil { result.FailWithMessage(ginI18n.MustGetMessage(c, "QRCodeGetFailed"), c) @@ -181,6 +188,7 @@ func (OAuthAPI) GetTempQrCode(c *gin.Context) { result.OK(ginI18n.MustGetMessage(c, "QRCodeGetSuccess"), data.Url, c) } +// wechatLoginHandler 微信登录处理 func wechatLoginHandler(openId string, clientId string) bool { if openId == "" { return false @@ -277,5 +285,9 @@ func handelUserLogin(user model.ScaAuthUser, clientId string) bool { if fail != nil || w != nil { return false } + res := websocket_api.SendMessageData(clientId, data) + if !res { + return false + } return true } diff --git a/api/user_api/user_api.go b/api/user_api/user_api.go index 17065a8..b1c6d24 100644 --- a/api/user_api/user_api.go +++ b/api/user_api/user_api.go @@ -4,7 +4,6 @@ import ( "encoding/json" ginI18n "github.com/gin-contrib/i18n" "github.com/gin-gonic/gin" - "github.com/wumansgy/goEncrypt/aes" "github.com/yitter/idgenerator-go/idgen" "reflect" "schisandra-cloud-album/api/user_api/dto" @@ -328,13 +327,7 @@ func (UserAPI) RefreshHandler(c *gin.Context) { result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) return } - plaintext, err := aes.AesCtrDecryptByHex(refreshToken, []byte(global.CONFIG.Encrypt.Key), []byte(global.CONFIG.Encrypt.IV)) - if err != nil { - global.LOG.Error(err) - result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c) - return - } - parseRefreshToken, isUpd, err := utils.ParseToken(string(plaintext)) + parseRefreshToken, isUpd, err := utils.ParseToken(refreshToken) if err != nil { global.LOG.Errorln(err) result.FailWithMessage(ginI18n.MustGetMessage(c, "LoginExpired"), c) diff --git a/api/websocket_api/websocket.go b/api/websocket_api/websocket.go new file mode 100644 index 0000000..5e60d52 --- /dev/null +++ b/api/websocket_api/websocket.go @@ -0,0 +1,4 @@ +package websocket_api + +type WebsocketAPI struct { +} diff --git a/api/websocket_api/websocket_api.go b/api/websocket_api/websocket_api.go new file mode 100644 index 0000000..164395d --- /dev/null +++ b/api/websocket_api/websocket_api.go @@ -0,0 +1,196 @@ +package websocket_api + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + "log" + "net/http" + "schisandra-cloud-album/global" + "sync" + "time" +) + +var ( + // 消息通道 + msg = make(map[string]chan interface{}) + // websocket客户端链接池 + client = make(map[string]*websocket.Conn) + // 互斥锁,防止程序对统一资源同时进行读写 + mux sync.Mutex +) + +// NewSocketClient 建立websocket长链接接口处理函数 +func (WebsocketAPI) NewSocketClient(context *gin.Context) { + id := context.Query("client_id") + global.LOG.Println(id + "websocket链接") + // 升级为websocket长链接 + WsHandler(context.Writer, context.Request, id) +} + +// DeleteClient api:/deleteClient接口处理函数 +func (WebsocketAPI) DeleteClient(context *gin.Context) { + id := context.Query("client_id") + // 关闭websocket链接 + conn, exist := getClient(id) + if exist { + err := conn.Close() + if err != nil { + return + } + deleteClient(id) + } else { + context.JSON(http.StatusOK, gin.H{ + "mesg": "未找到该客户端", + }) + } + // 关闭其消息通道 + _, exist = getMsgChannel(id) + if exist { + deletemsgChannel(id) + } +} + +// SendMessageData 发送消息接口处理函数 +func SendMessageData(clientId string, data interface{}) bool { + m, exist := getMsgChannel(clientId) + if !exist { + log.Println("未找到该客户端的消息通道") + return false + } + // 向消息通道发送消息 + select { + case m <- data: + global.LOG.Println("发送消息给客户端:" + clientId) + return true + default: + global.LOG.Println("消息通道已满,消息发送失败") + } + return false +} + +// websocket Upgrader +var wsupgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + HandshakeTimeout: 5 * time.Second, + // 取消ws跨域校验 + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +// WsHandler 处理ws请求 +func WsHandler(w http.ResponseWriter, r *http.Request, id string) { + var conn *websocket.Conn + var err error + var exist bool + // 创建一个定时器用于服务端心跳 + //pingTicker := time.NewTicker(time.Second * 10) + conn, err = wsupgrader.Upgrade(w, r, nil) + if err != nil { + global.LOG.Println(err) + return + } + // 把与客户端的链接添加到客户端链接池中 + addClient(id, conn) + + // 获取该客户端的消息通道 + m, exist := getMsgChannel(id) + if !exist { + m = make(chan interface{}) + addMsgChannel(id, m) + } + // 设置客户端关闭ws链接回调函数 + conn.SetCloseHandler(func(code int, text string) error { + deleteClient(id) + return nil + }) + defer conn.Close() + for { + _, _, err := conn.ReadMessage() + if err != nil { + fmt.Println(err) + return + } + select { + case content, _ := <-m: + // 从消息通道接收消息,然后推送给前端 + err = conn.WriteJSON(content) + if err != nil { + global.LOG.Error(err) + err := conn.Close() + if err != nil { + return + } + deleteClient(id) + break + } + //case <-pingTicker.C: + // // 服务端心跳:每20秒ping一次客户端,查看其是否在线 + // err := conn.SetWriteDeadline(time.Now().Add(time.Second * 20)) + // if err != nil { + // return + // } + // err = conn.WriteMessage(websocket.PongMessage, []byte("pong")) + // if err != nil { + // log.Println("send pong err:", err) + // err := conn.Close() + // if err != nil { + // return + // } + // deleteClient(id) + // return + // } + } + } + +} + +// 将客户端添加到客户端链接池 +func addClient(id string, conn *websocket.Conn) { + mux.Lock() + client[id] = conn + mux.Unlock() +} + +// 获取指定客户端链接 +func getClient(id string) (conn *websocket.Conn, exist bool) { + mux.Lock() + conn, exist = client[id] + mux.Unlock() + return +} + +// 删除客户端链接 +func deleteClient(id string) { + mux.Lock() + delete(client, id) + log.Println(id + "websocket退出") + mux.Unlock() +} + +// 添加用户消息通道 +func addMsgChannel(id string, m chan interface{}) { + mux.Lock() + msg[id] = m + mux.Unlock() +} + +// 获取指定用户消息通道 +func getMsgChannel(id string) (m chan interface{}, exist bool) { + mux.Lock() + defer mux.Unlock() + m, exist = msg[id] + return +} + +// 删除指定消息通道 +func deletemsgChannel(id string) { + mux.Lock() + if m, ok := msg[id]; ok { + close(m) + delete(msg, id) + } + mux.Unlock() +} diff --git a/core/wechat.go b/core/wechat.go index 6865f91..cee1f0d 100644 --- a/core/wechat.go +++ b/core/wechat.go @@ -12,7 +12,7 @@ func InitWechat() { AppID: "wx55251c2f83b9fc25", Secret: "d511800cd53d248afe1260bb8aeed230", Token: "LDQ20020618xxx", - AESKey: global.CONFIG.Wechat.AESKey, + AESKey: "", //Log: officialAccount.Log{ // Level: "debug", // File: "./wechat.log", @@ -23,7 +23,7 @@ func InitWechat() { Cache: kernel.NewRedisClient(&kernel.UniversalOptions{ Addrs: []string{global.CONFIG.Redis.Addr()}, Password: global.CONFIG.Redis.Password, - DB: 0, + DB: 2, }), }) if err != nil { diff --git a/go.mod b/go.mod index fbe79c8..3156628 100644 --- a/go.mod +++ b/go.mod @@ -49,6 +49,7 @@ require ( github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/go.sum b/go.sum index 10c9e5d..b1b754f 100644 --- a/go.sum +++ b/go.sum @@ -81,6 +81,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= diff --git a/router/modules/websocket_router.go b/router/modules/websocket_router.go new file mode 100644 index 0000000..ab12dff --- /dev/null +++ b/router/modules/websocket_router.go @@ -0,0 +1,17 @@ +package modules + +import ( + "github.com/gin-gonic/gin" + "schisandra-cloud-album/api" +) + +var websocketAPI = api.Api.WebsocketApi + +func WebsocketRouter(router *gin.RouterGroup) { + group := router.Group("/ws") + { + group.GET("/socket", websocketAPI.NewSocketClient) + group.GET("/delete", websocketAPI.DeleteClient) + } + +} diff --git a/router/router.go b/router/router.go index 4689bfe..baad8bc 100644 --- a/router/router.go +++ b/router/router.go @@ -22,10 +22,11 @@ func InitRouter() *gin.Engine { // 国际化设置 publicGroup.Use(middleware.I18n()) - modules.SwaggerRouter(router) // 注册swagger路由 - modules.UserRouter(publicGroup) // 注册鉴权路由 - modules.CaptchaRouter(publicGroup) // 注册验证码路由 - modules.SmsRouter(publicGroup) // 注册短信验证码路由 - modules.OauthRouter(publicGroup) // 注册oauth路由 + modules.SwaggerRouter(router) // 注册swagger路由 + modules.UserRouter(publicGroup) // 注册鉴权路由 + modules.CaptchaRouter(publicGroup) // 注册验证码路由 + modules.SmsRouter(publicGroup) // 注册短信验证码路由 + modules.OauthRouter(publicGroup) // 注册oauth路由 + modules.WebsocketRouter(publicGroup) // 注册websocket路由 return router } diff --git a/wechat/info.log b/wechat/info.log index 442057f..8ba7df9 100644 --- a/wechat/info.log +++ b/wechat/info.log @@ -27,3 +27,30 @@ {"L":"INFO","timestamp":"2024-08-15T21:48:35+08:00","M":"Server response created:","content":"7016009957992470331"} {"L":"INFO","timestamp":"2024-08-15T21:51:45+08:00","M":"Server response created:","content":"4905816075205062651"} {"L":"INFO","timestamp":"2024-08-15T23:24:38+08:00","M":"Server response created:","content":"3390456157377093054"} +{"L":"INFO","timestamp":"2024-08-16T19:22:07+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-16T19:22:07+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Fri, 16 Aug 2024 11:22:07 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66bf365f-74a75036-6e1d3867\"}"} +{"L":"INFO","timestamp":"2024-08-17T17:47:47+08:00","M":"Server response created:","content":"753244936953166311"} +{"L":"INFO","timestamp":"2024-08-17T18:16:27+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-17T18:16:27+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:16:27 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66c0787b-5e3675f0-195b0b61\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:16:55+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-17T18:16:55+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:16:55 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66c07897-09a3b67e-49f41f07\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:18:55+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-17T18:18:55+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:18:55 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66c0790f-59fe992c-18ed3d22\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:19:16+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-17T18:19:16+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:19:16 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66c07924-69688ba3-41062050\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:20:51+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-17T18:20:51+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:20:51 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66c07983-730549c5-59f35222\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:21:18+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=&grant_type=client_credential&neededText=&secret= request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-17T18:21:18+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 74\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:21:18 GMT\r\nLogicret: 41002\r\nRetkey: 11\r\n\r\n{\"errcode\":41002,\"errmsg\":\"appid missing rid: 66c0799e-158f8ada-60269170\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:22:54+08:00","M":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wx55251c2f83b9fc25&grant_type=client_credential&neededText=&secret=d511800cd53d248afe1260bb8aeed230 request header: { Accept:*/*} "} +{"L":"INFO","timestamp":"2024-08-17T18:22:54+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 173\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:22:54 GMT\r\n\r\n{\"access_token\":\"83_YrtFjPwib8kbGThSqqcLDXaz3LuRVOK4JbYO-Q1bcsHhQsSdldju-mp7Vspp_i7hp55s2moFMzwc58yBacSWpr-4qM8fdrSsbpoKm7dQrFsEFYDIPHTmR1dUnMoOHYiAEARKB\",\"expires_in\":7200}"} +{"L":"INFO","timestamp":"2024-08-17T18:22:54+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_YrtFjPwib8kbGThSqqcLDXaz3LuRVOK4JbYO-Q1bcsHhQsSdldju-mp7Vspp_i7hp55s2moFMzwc58yBacSWpr-4qM8fdrSsbpoKm7dQrFsEFYDIPHTmR1dUnMoOHYiAEARKB&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"c4093d33-5bc1-11ef-8f10-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"} +{"L":"INFO","timestamp":"2024-08-17T18:22:54+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:22:54 GMT\r\n\r\n{\"ticket\":\"gQFK8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyOUt5Tk5FbmxjbkYxUC02RXhDY3gAAgT_ecBmAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/029KyNNEnlcnF1P-6ExCcx\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:27:17+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_YrtFjPwib8kbGThSqqcLDXaz3LuRVOK4JbYO-Q1bcsHhQsSdldju-mp7Vspp_i7hp55s2moFMzwc58yBacSWpr-4qM8fdrSsbpoKm7dQrFsEFYDIPHTmR1dUnMoOHYiAEARKB&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"c4093d33-5bc1-11ef-8f10-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"} +{"L":"INFO","timestamp":"2024-08-17T18:27:18+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:27:18 GMT\r\n\r\n{\"ticket\":\"gQE48DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAySnZGdk5ibmxjbkYxTTU4RTFDY3MAAgQFe8BmAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02JvFvNbnlcnF1M58E1Ccs\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:27:44+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_YrtFjPwib8kbGThSqqcLDXaz3LuRVOK4JbYO-Q1bcsHhQsSdldju-mp7Vspp_i7hp55s2moFMzwc58yBacSWpr-4qM8fdrSsbpoKm7dQrFsEFYDIPHTmR1dUnMoOHYiAEARKB&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"c4093d33-5bc1-11ef-8f10-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"} +{"L":"INFO","timestamp":"2024-08-17T18:27:44+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:27:44 GMT\r\n\r\n{\"ticket\":\"gQEJ8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyaENjM044bmxjbkYxTXc4RWhDY3MAAgQge8BmAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02hCc3N8nlcnF1Mw8EhCcs\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:29:49+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_YrtFjPwib8kbGThSqqcLDXaz3LuRVOK4JbYO-Q1bcsHhQsSdldju-mp7Vspp_i7hp55s2moFMzwc58yBacSWpr-4qM8fdrSsbpoKm7dQrFsEFYDIPHTmR1dUnMoOHYiAEARKB&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"c4093d33-5bc1-11ef-8f10-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"} +{"L":"INFO","timestamp":"2024-08-17T18:29:50+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:29:49 GMT\r\n\r\n{\"ticket\":\"gQGE8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyVGxmRk1VbmxjbkYxT3Q4RTFDY2wAAgSde8BmAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02TlfFMUnlcnF1Ot8E1Ccl\"}"} +{"L":"INFO","timestamp":"2024-08-17T18:30:06+08:00","M":"POST https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=83_YrtFjPwib8kbGThSqqcLDXaz3LuRVOK4JbYO-Q1bcsHhQsSdldju-mp7Vspp_i7hp55s2moFMzwc58yBacSWpr-4qM8fdrSsbpoKm7dQrFsEFYDIPHTmR1dUnMoOHYiAEARKB&debug=1 request header: { Content-Type:application/jsonAccept:*/*} request body:{\"action_info\":{\"scene\":{\"scene_str\":\"7cd96062-5ade-11ef-9e17-902e16172287\"}},\"action_name\":\"QR_STR_SCENE\",\"expire_seconds\":2592000}\n"} +{"L":"INFO","timestamp":"2024-08-17T18:30:06+08:00","M":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 192\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Sat, 17 Aug 2024 10:30:06 GMT\r\n\r\n{\"ticket\":\"gQGi8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyT0tiYU0zbmxjbkYxT0s4RXhDY1AAAgSue8BmAwQAjScA\",\"expire_seconds\":2592000,\"url\":\"http:\\/\\/weixin.qq.com\\/q\\/02OKbaM3nlcnF1OK8ExCcP\"}"}