default_js_ticket.go 2.2 KB

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