nginx + lua 请求转发

记录一次

公众号大量同一时间发送模板,微信回调公众号告诉后台是否发送成功,因为没有业务处理,直接返回的success,报错Event=Template Send Job Finish。

这时候,nginx写了个转发到lua脚本处理请求,期间也出现过各种问题来阻碍我,简直疯了。实测有效~

-- 将请求交给PHP处理
function return_declined()
        ngx.req.set_uri('/' .. 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();