什麼?閘道器還有這種操作!
什麼?閘道器還有這種操作!
前提
以前我們專案都是單體專案,所有單位使用一個前端服務一個後端服務,近日由於有一個單位的資料庫連不上後端服務需要單獨部署在一臺伺服器上,但是前端還訪問以前的服務,這就需要我們對前端傳送的請求進行分流。
我們的每個介面都會有一個欄位進行區分是哪個單位的請求。所有我們就需要將這個單位的引數值單獨處理。
發現問題
我轉念一想這不就是再加一個閘道器就可以了嗎。於是乎我開始技術選型,本來打算用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。