default_js_ticket.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. return val.(string), nil
  50. }
  51. js.jsAPITicketLock.Lock()
  52. defer js.jsAPITicketLock.Unlock()
  53. // 双检,防止重复从微信服务器获取
  54. if val := js.cache.Get(jsAPITicketCacheKey); val != nil {
  55. return val.(string), nil
  56. }
  57. var ticket ResTicket
  58. ticket, err = GetTicketFromServerContext(ctx, accessToken)
  59. if err != nil {
  60. return
  61. }
  62. expires := ticket.ExpiresIn - 1500
  63. err = js.cache.Set(jsAPITicketCacheKey, ticket.Ticket, time.Duration(expires)*time.Second)
  64. ticketStr = ticket.Ticket
  65. return
  66. }
  67. // GetTicketFromServerContext 从服务器中获取ticket
  68. func GetTicketFromServerContext(ctx context2.Context, accessToken string) (ticket ResTicket, err error) {
  69. var response []byte
  70. url := fmt.Sprintf(getTicketURL, accessToken)
  71. response, err = util.HTTPGetContext(ctx, url)
  72. if err != nil {
  73. return
  74. }
  75. err = json.Unmarshal(response, &ticket)
  76. if err != nil {
  77. return
  78. }
  79. if ticket.ErrCode != 0 {
  80. err = fmt.Errorf("getTicket Error : errcode=%d , errmsg=%s", ticket.ErrCode, ticket.ErrMsg)
  81. return
  82. }
  83. return
  84. }