什么?网关还有这种操作!

什么?网关还有这种操作!

前提

以前我们项目都是单体项目,所有单位使用一个前端服务一个后端服务,近日由于有一个单位的数据库连不上后端服务需要单独部署在一台服务器上,但是前端还访问以前的服务,这就需要我们对前端发送的请求进行分流。
我们的每个接口都会有一个字段进行区分是哪个单位的请求。所有我们就需要将这个单位的参数值单独处理。

发现问题

我转念一想这不就是再加一个网关就可以了吗。于是乎我开始技术选型,本来打算用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。

上一篇:nginx+lua实现文件上传下载


下一篇:7.lua语法解析-token函数