如何處理大並發下微信公眾號模板消息回調


  目前我們部分公眾號粉絲量達到400萬以上,當給大量的粉絲發送模板消息的時候,微信會將如下xml的成功回調消息返給我們系統端造成短時間內系統壓力很大【目前是Nginx+PHP集群架構】,影響我們正常業務的處理,如何解決這個問題呢??

<xml> 
  <ToUserName><![CDATA[gh_7f083739789a]]></ToUserName>  
  <FromUserName><![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8]]></FromUserName>  
  <CreateTime>1395658920</CreateTime>  
  <MsgType><![CDATA[event]]></MsgType>  
  <Event><![CDATA[TEMPLATESENDJOBFINISH]]></Event>  
  <MsgID>200163836</MsgID>  
  <Status><![CDATA[success]]></Status> 
</xml>

  方案一:抽離出模板消息這個業務單獨用高性能的服務去處理這個請求。目前我們的業務場景不適合,因為模板消息里面包含了用戶信息、業務處理邏輯等。

  方案二:采用Nginx+Lua進行處理【業務中PHP框架導致請求一個hello world這樣簡單請求用時都在百毫秒左右】

    我采用Nginx+Lua 將回調成功的請求擋在調用后端服務前進行處理,具體方案如下:

  1. 微信公眾號后台配置回調地址【我們公眾號采用是第三方平台授權方式】配置位置如下:消息與事件接受URL https://abcapi.baidu.com/weixin/callback/$APPID$

     

     

  2. Nginx核心配置文件如下:
            location ^~ /weixin/callback/ {
                    default_type 'text/plain';
                    rewrite_by_lua_file 'conf/scripts/weixin_callback_filter.lua';
            }

     

  3. 核心lua 腳本如下:
    root@devops:/usr/local/nginx/conf/scripts# cat weixin_callback_filter.lua -- 將請求交給PHP處理 function return_declined() ngx.req.set_uri('/index.php' .. ngx.var.uri .. '?' .. ngx.var.args, true); ngx.exit(ngx.DECLINED); end -- 讀取請求體 ngx.req.read_body(); local content = ngx.req.get_body_data(); if (not content) then -- 如果請求體是空的, 不處理 return_declined(); end -- 如果含有TEMPLATESENDJOBFINISH字符串, 響應success local event = content:match('<Event><!%[CDATA%[(.*)]]></Event>'); if (event == 'TEMPLATESENDJOBFINISH' or event == 'VIEW') then ngx.say('success'); ngx.exit(ngx.HTTP_OK); end -- 讀取加密字符串 local encrypted = content:match('<Encrypt><!%[CDATA%[(.*)]]></Encrypt>'); if (not encrypted) then -- 如果加密字符串是空的, 不處理 return_declined(); else -- base64解碼 local _encrypted = ngx.decode_base64(encrypted); if (not _encrypted) then -- 解碼失敗? ngx.log(ngx.ERR, 'ngx.decode_base64() failed: ' .. encrypted); return_declined(); end encrypted = _encrypted; end -- 此處key需要替換為上圖中的消息加解密Key local aes_key = ngx.decode_base64('d9172b8a31042d1d60c8af719acddd89DdWeilyi663='); local aes = require 'resty.aes'; -- 解密 local decrypted = aes:new(aes_key, nil, aes.cipher(256, 'cbc'), {iv=aes_key:sub(0, 16)}, 5):decrypt(encrypted); if (not decrypted) then -- 解密失敗? ngx.log(ngx.ERR, 'openssl.cipher:decrypt() failed: ' .. content); return_declined(); end -- ngx.log(ngx.ERR, 'event: ' .. decrypted:match('<Event><!%[CDATA%[([%a]+)]')); -- 如果含有TEMPLATESENDJOBFINISH字符串, 響應success if (decrypted:find('TEMPLATESENDJOBFINISH') or decrypted:find('VIEW')) then ngx.say('success'); ngx.exit(ngx.HTTP_OK); end return_declined();
  4. 后期如果官方微信公眾號模板消息那邊發生變化的話,要根據實際情況對lua腳本進行修改
  5. 相關文章已同步到頭條號:不良帥的江湖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM