准备用nginx + lua + redis解决的问题
先不管注册登录的过程,假定已经登录。或者登录失效。前端每个请求,都要带上token令牌。
然后nginx接到请求后,将请求交给lua处理,这个时候,lua根据有无token令牌,并且通过redis校验token令牌是否合法,然后用结果对nginx的一个变量进行赋值。
然后nginx对这个变量进行判断,确定是跳转到登录页,还是返回请求需要的正确结果。
当用这个思想去实现时,遇到了不可逾越的问题。问题如下
问题
查看了很多资料,如下代码应该是可以进入if判断的,但是我怎么调都不进if,代码如下
location /test {
set $a 12;
set $b '';
rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1';
if ($b = '13') {
echo "222";
}
#echo "res = $b";
}
这是,从网上找到的一段代码,按理,应该是可以输出222,这一串数字的。但是我的环境怎么试都不行
心想,这lua要是不能修改nginx的变量,用lua岂不是很复杂了。觉得应该是自己的环境的问题。
重新搭个环境
历尽千辛万苦(其实不费事,嘿嘿),装好了一个centos虚机,开始安装OpenRestry
安装的过程请点击此处查看另外一篇文章。
但是,重新安装的虚机上,进行上述代码测试时,依然不能进入if内,输出222
思考
这个时候,我觉得,应该是if的代码和lua的代码不是同步的。才会导致这个问题。其实这个思路已经接近真相
只是自己一直被一个问题困扰,既然lua不能这么玩,那要怎么玩呢。
这之后一直在网上找资料。
曙光
在看了大量的资料后,有两个说法,我觉得是我解决问题的关键。
- 1、rewrite_by_lua的功能描述,和字面意思的理解,都有跳转的意思,那么是不是可以rewrite_by_lua代码的内部就可以跳转呢?资料给予的答案是肯定的。
- 2、不得不说网上关于lua的资料太少了,本该是一个大家都会跳的坑,愣是不能方便的搜索到解决方案。最终找到一份资料,确认了一个事实。nginx中的if会在rewrite_by_lua之前运行。至于echo为什么在rewrite_by_lua之后运行,并且输出被lua改变的变量值。还要后续进行深入的理解。这里不深入。
转换思维
其实,自己本身遇到这个问题,基于两点最根本的原因。
- 1、对nginx+lua不熟悉
- 2、已经有了实现登录状态处理的思维定式。顺着这个思维定式,注定要跳这个坑。
所以,在一直思考lua不能这么玩,该怎么玩的同时,了解到nginx和lua的一些特性,最终迸发出新的处理方式。
那就是,继续用rewrite_by_lua调用lua文件进行判断,只是,如果判断失效时,跳转到指定的登录页面,后续的nginx代码将被截断,不在执行。如果判断成功,则不进行任何处理,这样,当执行完lua文件后,自动继续nginx的处理,该反向代理就反向代理,该显示页面就显示页面。
最终测试时成功的,这里贴上测试的代码,当然,正式环境的代码要复杂的多。
- nginx.conf中的代码
user root;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
lua_code_cache off;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ^~ /api {
#在代理之前判断是否为有效登录
rewrite_by_lua_file "/usr/local/openresty/nginx/conf/loginresult";
#如果在rewrite_by_lua中没有跳转或者返回,则会运行下边的反向代理。
proxy_pass http://127.0.0.1:8095;
}
}
}
- loginresult文件中的代码
--接收access_token判断是否登录
local login_token = ngx.var.http_access_token
local login_user = ngx.var.http_user_name
local cjson = require("cjson")
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 1 sec
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say(cjson.encode({code = 500,message = "错误编号***,请联系系统维护人员进行处理!"}))
end
local result, err = red:get(login_token)
if not result then
local loginfailobj = {code = 500,message = "no login"}
local loginfailjson = cjson.encode(loginfailobj)
ngx.say(loginfailjson)
end
--如果存在登录信息,并且正确,则重新设定缓存存在时间,代码将来写在下边。
local ok, err = red:close()
结语:伴随着每一个困难问题的攻克,都会带给我愉悦的心情,这是我走在开发路上,前进的动力。
网友评论