default_js_ticket.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package credential
  2. import (
  3. context2 "context"
  4. "encoding/json"
  5. "fmt"
  6. "sync"
  7. "time"
  8. "github.com/silenceper/wechat/v2/cache"
  9. "github.com/silenceper/wechat/v2/util"
  10. )
  11. // getTicketURL 获取ticket的url
  12. const getTicketURL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"
  13. // DefaultJsTicket 默认获取js ticket方法
  14. type DefaultJsTicket struct {
  15. appID string
  16. cacheKeyPrefix string
  17. cache cache.Cache
  18. // jsAPITicket 读写锁 同一个AppID一个
  19. jsAPITicketLock *sync.Mutex
  20. }
  21. // NewDefaultJsTicket new
  22. func NewDefaultJsTicket(appID string, cacheKeyPrefix string, cache cache.Cache) JsTicketHandle {
  23. return &DefaultJsTicket{
  24. appID: appID,
  25. cache: cache,
  26. cacheKeyPrefix: cacheKeyPrefix,
  27. jsAPITicketLock: new(sync.Mutex),
  28. }
  29. }
  30. // ResTicket 请求jsapi_tikcet返回结果
  31. type ResTicket struct {
  32. util.CommonError
  33. Ticket string `json:"ticket"`
  34. ExpiresIn int64 `json:"expires_in"`
  35. }
  36. // GetTicket 获取jsapi_ticket
  37. func (js *DefaultJsTicket) GetTicket(accessToken string) (ticketStr string, err error) {
  38. return js.GetTicketContext(context2.Background(), accessToken)
  39. }
  40. // GetTicketFromServer 从服务器中获取ticket
  41. func GetTicketFromServer(accessToken string) (ticket ResTicket, err error) {
  42. return GetTicketFromServerContext(context2.Background(), accessToken)
  43. }
  44. // GetTicketContext 获取jsapi_ticket
  45. func (js *DefaultJsTicket) GetTicketContext(ctx context2.Context, accessToken string) (ticketStr string, err error) {
  46. // 先从cache中取
  47. jsAPITicketCacheKey := fmt.Sprintf("%s_jsapi_ticket_%s", js.cacheKeyPrefix, js.appID)
  48. if val := js.cache.Get(jsAPITicketCacheKey); val != nil {
  49. if ticketStr = val.(string); ticketStr != "" {
  50. return
  51. }
  52. }
  53. js.jsAPITicketLock.Lock()
  54. defer js.jsAPITicketLock.Unlock()
  55. // 双检,防止重复从微信服务器获取
  56. if val := js.cache.Get(jsAPITicketCacheKey); val != nil {
  57. if ticketStr = val.(string); ticketStr != "" {
  58. return
  59. }
  60. }
  61. var ticket ResTicket
  62. ticket, err = GetTicketFromServerContext(ctx, accessToken)
  63. if err != nil {
  64. return
  65. }
  66. expires := ticket.ExpiresIn - 1500
  67. err = js.cache.Set(jsAPITicketCacheKey, ticket.Ticket, time.Duration(expires)*time.Second)
  68. ticketStr = ticket.Ticket
  69. return
  70. }
  71. // GetTicketFromServerContext 从服务器中获取ticket
  72. func GetTicketFromServerContext(ctx context2.Context, accessToken string) (ticket ResTicket, err error) {
  73. var response []byte
  74. url := fmt.Sprintf(getTicketURL, accessToken)
  75. response, err = util.HTTPGetContext(ctx, url)
  76. if err != nil {
  77. return
  78. }
  79. err = json.Unmarshal(response, &ticket)
  80. if err != nil {
  81. return
  82. }
  83. if ticket.ErrCode != 0 {
  84. err = fmt.Errorf("getTicket Error : errcode=%d , errmsg=%s", ticket.ErrCode, ticket.ErrMsg)
  85. return
  86. }
  87. return
  88. }