首页 > 技术文章 > 钉钉开发系列(四)获取JS票据

sparkleDai 2016-05-23 18:00 原文

钉钉的客户端开发和服务端有一个重要的区别,服务端只需要得到access_token就可以了,而客户端还需要进一步换取jsticket。所以我们要进行客户端的开发,第一步就是得到jsticket。又由于jsticket有7200秒的限制,而且每请求一次前面的就会失效,为此我们需要做一个缓存层来保存。

首先我们来看缓存层的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDSDK
{
    /// <summary>
    /// 简易缓存
    /// </summary>
    public class SimpleCacheProvider : ICacheProvider
    {
        private static SimpleCacheProvider _instance = null;
        private readonly object _lockObj=new object();
        #region GetInstance
        /// <summary>
        /// 获取缓存实例
        /// </summary>
        /// <returns></returns>
        public static SimpleCacheProvider GetInstance()
        {
            if (_instance == null) lock(_lockObj){_instance =_instance?? new SimpleCacheProvider()};//使用单例模式以确保并发时实例始终是同一个
            return _instance;
        }
        #endregion

        private Dictionary<string, CacheItem> _caches;

        private SimpleCacheProvider()
        {
            this._caches = new Dictionary<string, CacheItem>();
        }

        #region GetCache
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object GetCache(string key)
        {
            object obj = this._caches.ContainsKey(key) ? this._caches[key].Expired() ? null : this._caches[key].Value : null;
            return obj;
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetCache<T>(String key)
        {
            object obj = GetCache(key);
            if (obj == null)
            {
                return default(T);
            }
            T result = (T)obj;
            return result;
        }
        #endregion

        #region SetCache
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expire"></param>
        public void SetCache(string key, object value, int expire = 300)
        {
            this._caches[key] = new CacheItem(key, value, expire);
        }
        #endregion
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDSDK
{
    /// <summary>
    /// 缓存接口
    /// </summary>
    interface ICacheProvider
    {
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns>缓存对象或null,不存在或者过期返回null</returns>
        object GetCache(string key);

        /// <summary>
        /// 写入缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存值</param>
        /// <param name="expire">缓存有效期,单位为秒,默认300</param>
        void SetCache(string key, object value, int expire = 300);
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDSDK
{
    /// <summary>
    /// 缓存项
    /// </summary>
    public class CacheItem
    {

        #region 属性
        private object _value;
        public object Value
        {
            get { return _value; }
            set { _value = value; }
        }

        private string _key;
        public string Key
        {
            get { return _key; }
            set { _key = value; }
        }
        #endregion

        #region 内部变量
        /// <summary>
        /// 插入时间
        /// </summary>
        private DateTime _insertTime;
        /// <summary>
        /// 过期时间
        /// </summary>
        private int _expire;
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="key">缓存的KEY</param>
        /// <param name="value">缓存的VALUE</param>
        /// <param name="expire">缓存的过期时间</param>
        public CacheItem(string key, object value, int expire)
        {
            this._key = key;
            this._value = value;
            this._expire = expire;
            this._insertTime = DateTime.Now();
        }
        #endregion

        #region Expired
        /// <summary>
        /// 是否过期
        /// </summary>
        /// <returns></returns>
        public bool Expired()
        {
            return DateTime.Now() < this._insertTime.AddSeconds(_expire);
        }
        #endregion
    }
}

代码中最关键的是缓存的单例GetInstance,这样确保了全局的一致性。如果需要进一步强化,可以考虑使用lock来实现更结实的单例模式。

下面我们来获取jsticket.

   #region FetchJSTicket Function  
        /// <summary>
        /// 获取JS票据
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static JSTicket FetchJSTicket()
        {
            var cache = SimpleCacheProvider.GetInstance();
            var jsTicket = cache.GetCache<JSTicket>(ConstVars.CACHE_JS_TICKET_KEY);
            if (jsTicket == null||AccessToken.Begin.AddSeconds(ConstVars.CACHE_TIME) < DateTime.Now)//jsTicket为null表示不存在或过期,或AccessToken过期
            {
                String apiurl = FormatApiUrlWithToken(Urls.get_jsapi_ticket);//该方法参看《钉钉开发系列(三)API的调用》
                jsTicket = Analyze.Get<JSTicket>(apiurl);
                cache.SetCache(ConstVars.CACHE_JS_TICKET_KEY, jsTicket, ConstVars.CACHE_TIME-500);//增加500的时间差以防与AccessToken错位过期
            }
            return jsTicket;
        }
        #endregion

namespace DDSDK
{
    /// <summary>
    /// JSAPI时用的票据
    /// </summary>
    public class JSTicket : ResultPackage
    {
        public string ticket { get; set; }
        public int expires_in { get; set; }
    }
}

调用FetchJsTicket就可以得到JS票据了,并且内部已经作了相应的缓存处理。

欢迎打描左侧二维码打赏。

转载请注明出处。

推荐阅读