对于手机游戏项目,大部分请求是带有用户属性的。首先,我们可以将请求区分的范围,缩小到同一用户的请求中。比如,在我们的项目中,通过传递 token 参数实现对用户身份的认证。 客户端在发送请求时,多传递一个 flag 参数,这是一个随机数。我们约定,客户端发送的每个新请求,都应该具有不同的 flag 值,而发送的重试请求,则使用失败的原请求的 flag 值。 服务端通过应答数据缓存和接收到请求的 flag 值,就可以区分是新请求还是重试请求。
local xxtea = loadMod("xxtea") local util = loadMod("core.util") local exception = loadMod("core.exception") local request = loadMod("core.request") local counter = loadMod("core.counter") local sysConf = loadMod("config.system") local changeLogger = loadMod("core.changes") local redis = loadMod("core.driver.redis") local cacheConf = loadMod("config.cache") local shmDict = loadMod("core.driver.shm") local shmConf = loadMod("config.shm")
--- Response模块 local Response = { --- 请求缓存键名前缀 CACHE_KEY_PREFIX: lastRes", --- Response存储处理器实例 cacheHelper = nil, } --- 生成重试缓存键名 -- -- @param number userId 用户ID -- @return string 重试缓存键名 function Response:getCacheKey(userId) return util:getCacheKey(self.CACHE_KEY_PREFIX, userId) end --- Response模块初始化 -- -- @return table Response模块 function Response:init() if sysConf.PRIORITY_USE_SHM then self.cacheHelper = shmDict:getInstance(shmConf.DICT_DATA) else self.cacheHelper = redis:getInstance(cacheConf.INDEX_CACHE) end return self end --- 发送应答 -- -- @param string message 应答数据 -- @param table headers 头设置 function Response:say(message, headers) ngx.status = ngx.HTTP_OK for k, v in pairs(headers) do ngx.header[k] = v end ngx.print(message) ngx.eof() end --- 构造并发送应答数据 -- -- @param table|string message 消息 -- @param boolean noCache 不缓存消息 function Response:send(message, noCache) local headers = { charset = sysConf.DEFAULT_CHARSET, content_type = request:getCoder():getHeader() } if sysConf.DEBUG_MODE then ngx.update_time() headers.mysqlQuery = counter:get(counter.COUNTER_MYSQL_QUERY) headers.redisCommand = counter:get(counter.COUNTER_REDIS_COMMAND) headers.execTime = ngx.now() - request:getTime() end if sysConf.ENCRYPT_RESPONSE then message = xxtea.encrypt(message, sysConf.ENCRYPT_KEY) end self:say(message, headers) if not noCache then local action = request:getAction() local token = request:getToken(false) local flag = request:getRandom() if token ~= "" and flag ~= "" then local cacheKey = self:getCacheKey(token) local cacheData = { action = action, flag = flag, headers = headers, reply = message } self.cacheHelper:set(cacheKey, cacheData, sysConf.REQUEST_RETRY_EXPTIME) end end end --- 检查重试请求,如果存在缓存则返回缓存 -- -- @return boolean function Response:checkRetry() local action = request:getAction() local token = request:getToken(false) local flag = request:getRandom() if token ~= "" and flag ~= "" then local cacheKey = self:getCacheKey(token) local cacheData = self.cacheHelper:get(cacheKey) if cacheData and cacheData.action == action and cacheData.flag == flag then self:say(cacheData.reply, cacheData.headers) return true end end return false end return Response:init()