什么?网关还有这种操作!
前提
以前我们项目都是单体项目,所有单位使用一个前端服务一个后端服务,近日由于有一个单位的数据库连不上后端服务需要单独部署在一台服务器上,但是前端还访问以前的服务,这就需要我们对前端发送的请求进行分流。
我们的每个接口都会有一个字段进行区分是哪个单位的请求。所有我们就需要将这个单位的参数值单独处理。
发现问题
我转念一想这不就是再加一个网关就可以了吗。于是乎我开始技术选型,本来打算用zuul,但是看到网上说zuul不再更新了,而且zuul2还没集成到SpringCloud,zuul性能不如gateway巴拉巴拉一大堆。我想那就用gateway吧。说干就干。经过我的研究gateway确实有根据请求参数值进行分流的功能而且直接在配置文件里面配置就可以了,顿时狂喜,心想果然是好框架,功能这么全面。
spring:
cloud:
gateway:
routes:
- id: ZZ
uri: localhost:8080
predicates:
- Query=code, ZZ
- id: HH
uri: localhost:8081
predicates:
- Query=code, HH
上面就是我测试的配置文件,如果请求中code参数值为ZZ就会把请求分到本机8080端口,参数值为HH就会把请求分到本机8081端口。于是我兴冲冲的用postman测试
网关绑定80端口
测试的没问题。
等到部署到服务器上,我一看,完全不能用,那个请求也不分到对应的服务上。我心想别慌,我们一点一点排查。先是在内网用postman测试post请求,请求正常分过去了。但是同样的参数在浏览器就不分流。百思不得其解。
后来我一看postman请求的url是将参数值加到了url后面。而我们用post方式提交都是将参数放在请求体里面。后面我将请求参数放到请求体里面用postman测试,果然网关不分流了。
顿时知道怎么回事了,postman不管发生什么请求只要在Params标签里面加参数就会把参数加到url后面,和get请求带参数一样。gateway根据参数值分流也只能根据url后面的参数进行分流,不能根据请求体里面的参数进行分流。既然这样不行,就想别的方法。
解决问题
平常我们做负载均衡都是用的nginx,我想是不是nginx也能根据请求参数值分流。在网上一查,使用nginx进行分流确实可以,但是需要给nginx所在的服务器安装lua开发环境,并且自己编写lua脚本来进行分流。我们的服务器又都是严格管理的不允许私自安装环境。这种方法又行不通了。偶然间看到了openresty这个中间件,百度了一下才知道这个软件是将nginx和lua集成在一起的web服务器,简单点说就是nginx的增强版,可以在里面编写lua脚本但是服务器不用安装lua环境。正合我意,可以对服务器进行最少的更改。于是乎经过我不懈的努力终于编写好了lua脚本。在这里我们值关注配置文件
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
lua_shared_dict shared_data 10m;
#gzip on;
server {
listen 9004;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location /api {
content_by_lua_file conf/lua/bureauanddept.lua;
}
location / {
proxy_pass http://127.0.0.1:8001;
}
location @lua_ZZ_api_suc {
proxy_pass http://127.0.0.1:8001;
}
location @lua_HH_api_suc {
proxy_pass http://10.3.90.214:9002;
}
location @lua_api_def {
proxy_pass http://127.0.0.1:8001;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
这是conf文件夹下nginx.conf配置文件,这里我们只关注53到63行。也就是@lua_ZZ_api_suc @lua_HH_api_suc @lua_api_def 这三个。
并且第47行我们指定了加载lua文件
local arg=nil
if request_method == "GET" then
arg = ngx.req.get_uri_args()
elseif request_method == "POST" then
local headers_tab = ngx.req.get_headers()
--先判断是不是上传文件
if (headers_tab["Content-Type"] == nil or string.match(headers_tab["Content-Type"],"multipart")=='multipart') then
return ngx.exec('@lua_api_def');
else
ngx.req.read_body()
arg = ngx.req.get_post_args()
end
end
--获得code值
local code = arg["code"]
--没有code值跳转到默认服务
if code == nil then
return ngx.exec('@lua_api_def');
--code值为ZZ跳转到ZZ服务
elseif code ~= nil and code == 'ZZ' then
return ngx.exec('@lua_ZZ_api_suc');
--code值为HH跳转到HH服务
elseif code ~= nil and code == 'HH' then
return ngx.exec('@lua_HH_api_suc');
--code值不是ZZ和HH跳转到默认服务
else
return ngx.exec('@lua_api_def');
end
这就是我们nginx.conf配置文件里面指定的lua文件。这里我们主要关注16行到29行。就是根据code的参数值分别跳转到指定的@lua_ZZ_api_suc @lua_HH_api_suc @lua_api_def。这里的名称和nginx.conf文件里的名称是一样的,而nginx.conf又指定了要跳转到那台服务。这样我们就实现了根据请求参数值的不同分流。
如需要源码请关注接地气程序员公众号号后添加作者微信领取。
如果本篇文章对您有帮助,不妨点个关注。
接地气的程序员,接地气的bug。