实现功能:
1,支持http查询lua_shared2,支持redisCluster动态路由
3,支持业务日志收集(大字段不考虑)
4,支持日志切割(linux-shell)
5,支持upstream动态扩容并持久化
6,支持nginx应用与配置分离运行(Linux-shell)
7,支持Jenkins一键自动部署.zip(windows-cmd)
8,支持prometheus指标监控
用到的模块(升级openresty很多都自带):
1,LuaJIT-2.0.4.tar.gz2,luafilesystem-v_1_6_3.tar.gz
3,lua-nginx-module-0.10.8.zip
4,lua-resty-redis-cluster-master.zip
5,lua-resty-redis-master.zip
6,nginx-clojure-0.4.5.tar.gz(nginx调用java时用)
7,ngx_http_dyups_module-0.2.9.zip
8,redis2-nginx-module-0.14.zip
整体思路:
1,请求通过F5路由到下面的4台nginx,nginx通过url拦截解析request header,request body 获取到对应的路由key(apiSign,其实是业务method拼接)通过调用redisCluster返回对应的upstreamName路由,顺便收集全量的请求响应信息(包括多次请求,会涉及到nginx执行顺序)json
2,对收集到的日志在做处理,切割,通过logstash入kafka(也可以直接对接kafka,但可能因为kafka故障丢失数据)
3,动态扩容是临时加减服务器(server应用)以及对upstream的增删改查操作,通过ngx_http_dyups_module模块完成,支持rest,我的实现思路是:将upstream抽成独立文件include加载,nginx启动初始化时,读一份upstream lua_shared做备份(upstreamName,value),http请求操作upstream时,则拦截request_body,通过ngx.location.capture方式操作nginx内存,如果res返回成功,则将request_body处理,写入到lua_shared,并更新upstream File(这里有个坑,ngx_http_dyups_module模块,sprintf做的不是太友好,不完全,没有显示全部的upstream信息,如果显示全部的信息,则可以每次调用http直接操作nginx内存,然后调用ngx.location.capture detail
方法拿到全量的upstream list 直接写入upstream File)
4,Jenkins自动部署则因为这边是一份代码区分N个环境,则需要创建多个job,通用win-cmd命令(Jenkins是win版,汗,如果linux版更容易)
上传代码
nginx.conf
#运行用户和组,缺省为nobody,若改为别的用户和组,则需要先创建用户和组
#user wls81 wls;
#开启进程数,一般与CPU核数等同
worker_processes 4;
#设置进程到cpu(四cpu:0001 0010 0100 1000)
#worker_cpu_affinity 0001 0010 0100 1000;
#每个进程最大打开文件数
worker_rlimit_nofile 8000;
#进程号保存文件
#pid /wls/apache/applogs/ng_sbtps-opf-dmzweb-nginx/nginx.pid;
#error_log logs/error.log;
pid logs/nginx.pid;
#设置错误日志
#error_log /wls/apache/applogs/ng_sbtps-opf-dmzweb-nginx/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
events
{
#运行模式设置[ kqueue | rtsig | epoll | /dev/poll | select | poll ];
#使用epoll(linux2.6的高性能方式)
use epoll;
#每个进程最大连接数(最大连接=连接数x进程数)
worker_connections 8000;
}
http
{
#文件扩展名与文件类型映射表
#include mime.types;
#默认文件类型
#default_type text/html;
default_type application/octet-stream;
#服务器名称相关设置
server_names_hash_max_size 256;
server_names_hash_bucket_size 512;
#默认编码
charset UTF-8;
#开启高效文件传输模式,直接从系统级别传输(Linux 2.4以上支持,纯文件服务器才能打开)
sendfile off;
#网络TCP_NOPUSH和TCP_NODELAY参数设置
#tcp_nopush on;
tcp_nodelay on;
#设置保留链接超时时间为75秒 设置header超时时间为20秒
keepalive_timeout 75 20;
#打开gzip压缩
gzip on;
#最小压缩文件大小
gzip_min_length 1K;
#压缩缓冲区
gzip_buffers 4 8k;
#压缩类型
gzip_types text/* text/css application/javascript application/x-javascript application/xml;
#压缩级别 1-9 1最快 9最慢
gzip_comp_level 9;
#压缩通过代理的所有文件
gzip_proxied any;
#vary header支持
gzip_vary on;
#压缩版本(默认1.1,前端为squid2.5使用1.0)
gzip_http_version 1.1;
#输出缓冲区
output_buffers 4 32k;
#输出拆包大小
postpone_output 1460;
#接收header的缓冲区大小
client_header_buffer_size 128k;
large_client_header_buffers 4 256k;
#客户端发送header超时
client_header_timeout 3m;
#客户端发送内容超时
client_body_timeout 3m;
#发送到客户端超时
send_timeout 3m;
#捕捉代理端的http错误
#proxy_intercept_errors on;
#日志文件格式
log_format main '$remote_addr $http_x_forwarded_for $remote_user $time_iso8601 $status '
'$server_protocol $request_id $comp_sign $request_method $reSetReqUri $uri $http_referer $gzip_ratio '
'"$http_user_agent" '
'$body_bytes_sent $bytes_sent $request_length "$upstream_addr" "$upstream_header_time" "$upstream_response_time" $request_time';
log_format requestBody '$remote_addr - $remote_user [$time_local] "$request" '
'"$status" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" logTraceId:$request_id $comp_sign $request_method $apiSign req_body:"$request_body" resp_body:"$resp_body" resp_map:"$resp_map"'
'$upstream_addr $bytes_sent $request_length "$upstream_response_time" "$request_time"';
lua_need_request_body on;
#日志文件(不记录)
#access_log /dev/null;
#access_log logs/access.log main;
#error_log /wls/appsystems/nginx/openresty-1.11.2.4/nginx/logs/error.log error;
#默认主机配置
#include default_host.conf;
#包含其它虚拟主机配置;
include servers/*.com;
include servers/*.net;
include servers/*.org;
include servers/*.cn;
}
sbtps-opf-ngx-sf-nginx.cominclude /wls/appsystems/nginx/servers/conf/servers/respCodeMap.map;
#api映射配置
lua_shared_dict apiMappingShared 50m;
lua_shared_dict healthStatus 1m;
lua_shared_dict redisSwitchShared 256k;
lua_shared_dict prometheus_metrics 10M;
client_body_buffer_size 100m;
client_max_body_size 100m;
lua_shared_dict upstreamShared 64m; # 定义upstream共享内存空间
#init_worker_by_lua_file conf/scripts/luas/init.lua;
init_by_lua_file /wls/appsystems/nginx/servers/conf/scripts/luas/init.lua;
#获取访问客户的真实IP
map $http_x_forwarded_for $clientRealIp {
"" $remote_addr;
~^(?P[0-9\.]+),?.*$ $firstAddr;
}
#限制客户端的访问频次,这里限制每秒20次上限
limit_req_zone $clientRealIp zone=SF-WEB-AUTHAPP-LIMIT:10m rate=100r/s;
#配置负载均衡服务器(采用IP Hash算法,相同客户IP会转发到相同服务器)
server
{
#设置监听端口
listen 37775 default;
#设置服务器域名(IP访问和多域名访问可不设置)
#server_name _*;
#server_name www.test.com;
#开启shtml支持
#ssi on;
#ssi_silent_errors on;
#ssi_types text/shtml;
#设置主访问日志
#access_log /wls/appsystems/nginx/openresty-1.11.2.4/nginx/logs/access.log main;
#access_log /wls/appsystems/nginx/openresty-1.11.2.4/nginx/logs/requestBody.log requestBody;
error_log logs/error.log error;
access_log logs/access.log main;
error_log logs/request.log notice;
##定义$networkSign的值,区别内网外网
set $networkSign "OPENAPI_NGINX_ROUTE_NODE_LAN";
##定义$request_trace_id的值,在1.11.x之前,我们可以使用类似的方式声明,只要能确保
##其值出现重复的可能性尽可能的小即可。
set $request_trace_id trace-id-$pid-$connection-$bytes_sent-$msec;
set $comp_sign "";
set $reSetReqUri $request_uri;
set $resp_body "";
set $resp_map "";
set $apiSign "";
#access_log /dev/null;
#fastcgi_intercept_errors on;
#error_page 404 403 = /404.html;
#error_page 500 502 503 504 = /50x.html;
include /wls/appsystems/nginx/servers/conf/servers/server-http-error-page.err;
#设置转发到跟投APP后端服务器的URL(正则表达式)
#location ~ (^/pa/interface/jk/(cgi-bin|servlet|chart)/|\.jsp$)
#{
#proxy_pass http://backendServer;
#include proxy.conf;
#}
#设置转发到后端服务器的URL(正则表达式)
#location ~ (^/pa/newstock/hq/(cgi-bin|servlet|chart)/|\.jsp$)
#{
#proxy_pass http://backendServer;
#include proxy.conf;
#}
#设置监控nginx状态URL
location /__nginxstatus
{
stub_status on;
access_log off;
}
location ^~ /reloadApiMapping {
default_type "text/plain";
content_by_lua '
ngx.log(ngx.ERR,"this is reloadApiMapping configuration !")
require("apiMapping");
apiMapping.reloadApiMapping();
';
}
location ^~ /setRedisSwitch {
default_type "text/plain";
content_by_lua '
ngx.log(ngx.ERR,"this is setRedisSwitch configuration !")
require("apiMapping");
apiMapping.setRedisSwitch();
';
}
location ^~ /getLuaShared {
default_type "text/plain";
content_by_lua '
ngx.log(ngx.ERR,"this is getLuaShared configuration !")
require("apiMapping");
apiMapping.getLuaShared();
';
}
location /metrics {
access_log off;
content_by_lua '
--ngx.log(ngx.ERR,"this is metrics configuration !")
metric_connections:set(ngx.var.connections_reading, {"active"})
metric_connections:set(ngx.var.connections_reading, {"reading"})
metric_connections:set(ngx.var.connections_waiting, {"waiting"})
metric_connections:set(ngx.var.connections_writing, {"writing"})
prometheus:collect()
';
}
location /favicon.ico {
log_not_found off;
access_log off;
}
location ^~ /detail {
dyups_interface; # 这个指令表示这边是接口站点
lua_need_request_body on;
}
location ^~ /upstream {
dyups_interface; # 这个指令表示这边是接口站点
lua_need_request_body on;
}
location ^~ /upstreamMain {
dyups_interface; # 这个指令表示这边是接口站点
lua_need_request_body on;
content_by_lua '
--ngx.log(ngx.ERR,"this is nginx-upstreamMain operation !")
require("upstreamdynamic");
upstreamdynamic.run();
';
}
location ^~ /beat/checkSet {
default_type "text/plain";
content_by_lua '
local reqUri = ngx.var.uri;
local status=string.sub(reqUri,16,-1);
local healthStatus = ngx.shared.healthStatus;
healthStatus:set("status", status);
local data = {};
data["status"]=status;
ngx.say(cjson.encode(data));
';
}
location ^~ /beat/check {
default_type "text/plain";
access_log off;
content_by_lua '
local healthStatus = ngx.shared.healthStatus;
local status = healthStatus:get("status");
if status == nil or status=="" then
status ="UP"
end
local data = {};
data["status"]=status;
ngx.say(cjson.encode(data));
';
}
#设定根目录(若全部请求转发到后端服务器则不需要设置)
location /
{
#web根目录,根据实际情况调整
#limit_req zone=SF-WEB-AUTHAPP-LIMIT nodelay;
#proxy_pass http://SF-WEB-AUTHAPP/;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header logTraceId $request_id;
set $comp_sign AUTH2;
set $reSetReqUri $request_uri;
set $redisResultJson "";
lua_need_request_body on;
#set $resp_map "";
rewrite_by_lua 'apiMapping.getCompSign()';
body_filter_by_lua '
--ngx.log(ngx.ERR,"this is nginx-request configuration !")
require("request");
request.run();
';
proxy_set_header X-Request-ID $request_id;
proxy_pass http://$comp_sign/AuthApp$reSetReqUri;
log_by_lua '
--ngx.log(ngx.ERR,"this is nginx-logout configuration !")
require("logout");
logout.run();
';
}
}
server-http-error-page.errerror_page 404 = /httpStatusRewrite?apiRespCodeParam=-10201;
error_page 403 = /httpStatusRewrite?apiRespCodeParam=-5;
error_page 503 = /httpStatusRewrite?apiRespCodeParam=-6;
error_page 500 502 504 = /httpStatusRewrite?apiRespCodeParam=-1;
location /httpStatusRewrite{
default_type "text/plain";
set $apiRespCode $arg_apiRespCodeParam;
if ( $apiRespMsg = '' ) {
return 200 '{"resCode":"-1","resMsg":"请求失败"}';
}
return 200 '{"resCode":"$apiRespCode","resMsg":"$apiRespMsg"}';
}
respCodeMap.mapmap $apiRespCode $apiRespMsg {
"0" "SUCCESS。";
"-10000" "参数不可为空。";
"-1" "请求失败。";
"-5" "禁止访问。";
"-6" "访问频率过快,请稍后再试。";
"-10201" "未定义路径。";
"-1006" "参数格式异常。";
"-1013" "目前仅支持POST请求方式。";
}
upstream.comupstream SBTPS-OPF-AIO-WEB-SF-AUTH-APP-MACS
{
server 10.17.144.176:8080;
server 10.17.144.177:8080;
keepalive 1024;
}
upstream SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS
{
server 10.17.145.86:30074;
server 10.17.145.87:30074;
server 10.17.145.94:30074;
server 10.17.145.95:30074;
keepalive 1024;
}
upstream SBTPS-OPF-AIO-WEB-SF-AUTH-APP-YDKH
{
server 10.17.145.88:30074;
server 10.17.145.89:30074;
keepalive 1024;
}
upstream SBTPS-OPF-AIO-WEB-SF-AUTH-APP-TDX
{
server 10.17.145.94:30074;
server 10.17.145.95:30074;
keepalive 1024;
}
upstream SBTPS-OPF-AIO-WEB-SF-AUTH-APP-KH-IDVERIFY
{
server 10.17.145.96:30074;
server 10.17.145.97:30074;
keepalive 1024;
}
upstream SBTPS-OPF-AIO-WEB-WEBII-AUTH-APP
{
server 10.17.167.133:8080;
server 10.17.167.134:8080;
keepalive 1024;
}
upstream SBTPS-OPF-AIO-WEB-DMZPTR-AUTH-APP
{
server 10.17.145.94:30074;
server 10.17.145.95:30074;
keepalive 1024;
}
init.luafunction init()
cjson = require "cjson";
lfs = require "lfs"
local __FILE__ = debug.getinfo(1,'S').source:sub(2)
--获取当前执行脚本的文件名以及所在路径
--SCRIPT_ROOT_PATH:/wls/appsystems/nginx20170714/openresty-1.11.2.4/nginx/conf/scripts/luas/
SCRIPT_ROOT_PATH = dirname(__FILE__);
--upstreamFile = SCRIPT_ROOT_PATH.."../../servers/upstream.com";
initLuaModule()
local LATENCY_BUCKETS = {0.05, 0.2, 0.5, 1, 5, 10}
local BYTESIZE_BUCKETS = {1, 3, 5, 10, 15 , 20}
prometheus = require("prometheus").init("prometheus_metrics")
--counter metrics for host+upstream
metric_requests = prometheus:counter("openapi_nginx_http_requests_total", "Number of HTTP requests", {"host","upstream", "status"})
--metric_ssorequests = prometheus:counter("nginx_http_sso_requests_total", "Number of HTTP sso requests", {"status"})
--gauge metrics
metric_connections = prometheus:gauge("openapi_nginx_http_connections", "Number of HTTP connections", {"state"})
--histogram metrics for upstream
metric_latency = prometheus:histogram("openapi_nginx_http_request_duration_seconds", "HTTP request latency", {"upstream"}, LATENCY_BUCKETS)
--metric_ssolatency = prometheus:histogram("nginx_http_sso_duration_seconds", "HTTP sso request latency",{}, LATENCY_BUCKETS)
metric_bytes = prometheus:histogram("openapi_nginx_http_request_bytes_sent", "HTTP responses size", {"upstream"}, BYTESIZE_BUCKETS)
apiMapping = require "apiMapping"
apiMapping.init()
upstreamdynamic = require "upstreamdynamic"
upstreamdynamic.init()
redisClusterConfig()
end
function dirname(str)
if str:match(".-/.-") then
local name = string.gsub(str, "(.*/)(.+)", "%1")
return name
elseif str:match(".-\\.-") then
local name = string.gsub(str, "(.*\\)(.+)", "%1")
return name
else
return ''
end
end
--/wls/apache/appsystems/ng_sis-stock-frontend-restapi/wwwroot/lua/project_init.lua
--- 当前文件名
--local __FILE__ = debug.getinfo(1,'S').source:sub(2)
--/wls/apache/appsystems/ng_sis-stock-frontend-restapi/wwwroot/lua/
--lua_package_path "$prefix/?.lua;;";
--local script_root = dirname(__FILE__);
function initLuaModule(rootPath)
--local rootPath=SCRIPT_ROOT_PATH..'scripts/luas/';
local rootPath=SCRIPT_ROOT_PATH;
getpathes(rootPath, nil);
end
function getpathes(rootpath, pathes)
pathes = pathes or {}
local attr = lfs.attributes(rootpath)
if attr and attr.mode == 'directory' then
package.path = string.format("%s?.lua;%s", rootpath, package.path)
for entry in lfs.dir(rootpath) do
if entry ~= '.' and entry ~= '..' then
getpathes(rootpath .. entry.. '/', pathes)
end
end
end
return pathes
end
function redisClusterConfig()
local config = {
name="openapi",
serv_list = {
{ip="10.25.174.28", port = 6001},
{ip="10.25.174.28", port = 6002},
{ip="10.25.174.28", port = 6003},
{ip="10.25.174.28", port = 7001},
{ip="10.25.174.28", port = 7002},
{ip="10.25.174.28", port = 7003},
{ip="10.25.174.28", port = 6001},
{ip="10.25.174.28", port = 6002},
},
keepalive_timeout = 200,
keepalove_cons = 20
}
ngx.shared.redisClusterConfig = config;
--networkSign = "OPENAPI_NGINX_ROUTE_NODE_LAN";--内网
--networkSign = "OPENAPI_NGINX_ROUTE_NODE_WAN";--外网
end
init();
apiMapping.luaapiMapping={};
apiMapping.mappingJsonFile=SCRIPT_ROOT_PATH.."modules/apimapping/apiMapping.json";
function apiMapping.init()
--local cjson = require "cjson";
local apiMappingShared = ngx.shared.apiMappingShared;
local redisSwitchShared = ngx.shared.redisSwitchShared;
local file = io.open(apiMapping.mappingJsonFile, "r");
local ret,pcallBack=pcall(parseJson,file:read("*all"));
file:close();
if ret then
apiMappingShared:flush_all();
for name, value in pairs(pcallBack) do
--ngx.log(ngx.NOTICE,"name:"..name.."||".."value:"..cjson.encode(value));
apiMappingShared:set(name, cjson.encode(value));
end
else
ngx.log(ngx.ERR,"init method,JSON PARSE apiMapping.json error.");
end
redisSwitchShared:set("redisSwitch","true");
end
function getRequestArgs()
local args = ngx.req.get_uri_args()
local requestArgs = {};
for key, value in pairs(args) do
if type(value) == "table" then
--ngx.log(ngx.ERR,"key:"..key.."value:"..value)
--ngx.say(key, ": ", table.concat(value, ", "))
requestArgs[key] = table.concat(value, ", ")
else
requestArgs[key] = value
--ngx.log(ngx.ERR,"key:"..key.."value:"..value)
--ngx.say(key, ": ", value)
end
end
return requestArgs;
end
function apiMapping.getLuaShared()
local request_method = ngx.var.request_method;
local url = ngx.var.uri;
local args = strSplit("/",url);
local requestArgs = getRequestArgs();
--ngx.log(ngx.ERR,"requestArgs:"..cjson.encode(requestArgs))
local apiMappingShared = ngx.shared.apiMappingShared;
local redisSwitchShared = ngx.shared.redisSwitchShared;
local upstreamShared = ngx.shared.upstreamShared;
if request_method ~= "GET" then
ngx.say("此getLuaShared接口仅支持GET请求方式。")
return
end
if #args>=4 then
ngx.say("getLuaShared接口查询格式不对!")
return
end
--ngx.log(ngx.ERR,"args[3]:"..args[3])
local tableTemp={};
if args[3] == "redisSwitchShared" then
if next(requestArgs) ~= nil then
for key, value in pairs(requestArgs) do
if key == "key" and value == "flag" then
local v = redisSwitchShared:get("redisSwitch");
tableTemp[value] = v;
end
end
end
end
if args[3] == "apiMappingShared" then
if next(requestArgs) ~= nil then
for key, value in pairs(requestArgs) do
if key == "key" and value == "all" then
local keys = apiMappingShared:get_keys(1024);
--ngx.log(ngx.ERR,"keys"..cjson.encode(keys));
for index, key in pairs(keys) do
local v = apiMappingShared:get(key);
tableTemp[key]=v
end
else
local v = apiMappingShared:get(value);
tableTemp[value]=v;
--ngx.say("查询apiMappingShared的key:"..value.."||".."value:"..cjson.encode(v))
end
end
end
end
if args[3] == "upstreamShared" then
if next(requestArgs) ~= nil then
for key, value in pairs(requestArgs) do
if key == "key" and value == "all" then
local keys = upstreamShared:get_keys(1024);
--ngx.log(ngx.ERR,"keys"..cjson.encode(keys));
for index, key in pairs(keys) do
local v = upstreamShared:get(key);
tableTemp[key]=v
end
else
local v = upstreamShared:get(value);
tableTemp[value]=v;
--ngx.say("查询apiMappingShared的key:"..value.."||".."value:"..cjson.encode(v))
end
end
end
end
if next(tableTemp) ~= nil then
ngx.say(cjson.encode(tableTemp));
--ngx.log(ngx.ERR,"tableTemp:"..cjson.encode(tableTemp));
else
ngx.say("查询信息不存在~!");
end
end
function parseJson(jsonString)
if jsonString then
--local cjson = require "cjson"
--parse json
local data= cjson.decode(jsonString);
--ngx.say(data["appId"])
return data;
else
return nil;
end
end
function httpPostParamReaderByReloadApiMapping()--专门为apiMapping.reloadApiMapping()所用
-- read post data
--server中使用lua_need_request_body on; 或者在location lua代码块中使用 ngx.req.read_body(),日志中能获取$request_body
ngx.req.read_body()
local data = ngx.req.get_body_data()
local postData = nil;
local ret,backData=pcall(parseJson,data);
if ret then
postData = backData;
else
ngx.log(ngx.ERR,"reloadApiMapping JSON PARSE apiMapping post json data error.");
end
return postData;
end
function copyfile(source,destination)
sourcefile = io.open(source,"r")
destinationfile = io.open(destination,"w")
for line in sourcefile:lines() do
destinationfile:write(line)
end
sourcefile:close()
destinationfile:close()
end
function printCaptureResult(code)
local responseBody =ngx.location.capture("/httpStatusRewrite?apiRespCodeParam="..code);
ngx.say(responseBody['body'])
ngx.exit(ngx.HTTP_OK)
--ngx.say(msg)
end
function routeLocation(apiSign)
--local responseBody =ngx.location.capture("/springboot/"..apiSign);
local responseBody =ngx.location.capture("/springboot?cacheKey="..apiSign);
--ngx.log(ngx.ERR,"this is routeLocation:"..apiSign);
--ngx.log(ngx.ERR,"the responseBody.status is :"..responseBody.status);
--ngx.log(ngx.ERR,"the responseBody.body is :"..responseBody.body);
return responseBody.body
end
function getRedisClusterCompSign(apiSign)
local redis_cluster = require "resty.rediscluster";
local red = redis_cluster:new(ngx.shared.redisClusterConfig);
--local KEY_NAME = "OPENAPI_NGINX_ROUTE_NODE_LAN";--内网
--local KEY_NAME = "OPENAPI_NGINX_ROUTE_NODE_WAN";--外网
--local res = red:init_pipeline()
--ngx.log(ngx.ERR,"config.redis_keepalive_timeout is :"..red.config.keepalive_timeout)
--ngx.log(ngx.ERR,"apiSign is :"..apiSign)
--ngx.log(ngx.ERR,"KEY_NAME is :"..KEY_NAME)
--red:set("forward_sbtpsboa_queryIPOsSecuInfo", "SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS")
--red:set(apiSign, "SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS")
--local results, err = red:get("forward_sbtpsboa_queryIPOsSecuInfo")
--local results, err = red:get(apiSign)
local networkSign = ngx.var.networkSign;
--ngx.log(ngx.ERR,"networkSign is :"..networkSign)
local results, err = red:hget(ngx.var.networkSign,apiSign)--networkSign在init.lua中定义
--red:close()
--local results, err = red:commit_pipeline()
--local cjson = require "cjson"
--ngx.log(ngx.ERR,"result is :"..cjson.encode(results))
if not results then
ngx.log(ngx.ERR,"failed to get apiSign: "..err)
return
end
if type(results) == "userdata" then--redis get nil
return nil
end
--ngx.log(ngx.ERR,"results is :"..results);
return results
end
function apiMapping.setRedisSwitch()
local redisSwitchShared = ngx.shared.redisSwitchShared;
local requestArgs = getRequestArgs();
--ngx.log(ngx.ERR,"requestArgs:"..cjson.encode(requestArgs))
if next(requestArgs) ~= nil then
for key, value in pairs(requestArgs) do
if key == "flag" then
redisSwitchShared:set("redisSwitch",value);
ngx.say("设置查询redis开关:"..key.." = "..value)
end
end
end
end
function apiMapping.reloadApiMapping()
--local postBody = httpPostParamReader();
local postBody = httpPostParamReaderByReloadApiMapping();
local apiMappingShared = ngx.shared.apiMappingShared;
if postBody then
--apiMappingShared:flush_all();
--ngx.log(ngx.NOTICE,"1:apiMappingShared.get.forward_kess_idVerify :"..apiMappingShared:get("forward_kess_idVerify"))
local confJson = {};
for apiSign, compSign in pairs(postBody) do
--ngx.say(table2str(mapping))
confJson[apiSign]=compSign;
apiMappingShared:set(apiSign,cjson.encode(compSign));
--ngx.log(ngx.NOTICE,"name:"..apiSign.."||".."value:"..cjson.encode(compSign));
--ngx.log(ngx.NOTICE,"apiMappingShared.get.apiSign:".."||"..apiMappingShared:get("forward_xjb_updateAgmt"));
end
--ngx.log(ngx.NOTICE,"2:apiMappingShared.get.forward_kess_idVerify :"..apiMappingShared:get("forward_kess_idVerify"))
--ngx.log(ngx.NOTICE,"confJson:"..cjson.encode(confJson));
local bakFile=apiMapping.mappingJsonFile..".bak";
copyfile(apiMapping.mappingJsonFile,bakFile);
local f=io.open(apiMapping.mappingJsonFile,"w+")
f:write("{\n");
if next(confJson) ~=nil then
local idx =1;
for key, value in pairs(confJson) do
if idx>1 then
f:write(",\n");
end
f:write("\""..key.."\":"..cjson.encode(value));
--f:write("\""..key.."\":".."\""..value.."\"");
f:flush()
idx = idx+1;
end
end
f:write("\n}");
f:close();
printCaptureResult(0);
--ngx.location.capture("/httpStatusRewrite?apiRespCodeParam=0");
--ngx.say("success");
else
printCaptureResult(-10000)
--ngx.say("empty request data");
end
end
function readGetTypeParam(source)
local nSplitArray = {}
local head = {}
local body = {}
for match in (source):gmatch("(.-)" .. "&" .. "()" ) do
local equalIdx = string.find(match,"=");
if equalIdx then
local paramName = string.sub(match, 1, equalIdx-1) ;
local paramValue = string.sub(match, equalIdx+1, string.len(match)) ;
if paramName == "requestParam" then
paramName = string.match(paramName,"%s*(.-)%s*$");
if paramValue then
paramValue = string.match(paramValue,"%s*(.-)%s*$");
end
--print("put param :"..paramName.."|"..paramValue)
body[paramName] = paramValue;
elseif paramName and paramName ~= "requestParam" then
paramName = string.match(paramName,"%s*(.-)%s*$");
if paramValue then
paramValue = string.match(paramValue,"%s*(.-)%s*$");
end
head[paramName] = paramValue;
else
return false,nil;
end
end
end
nSplitArray["head"] = head;
nSplitArray["body"] = body;
return true,nSplitArray;
end
function decodeURI(s)
if s ~= nil then
return string.gsub(s, '%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end)
else
return nil
end
end
--URL decode 转换
function escape(s)
if s ~= nil then
return string.gsub(s, "([^A-Za-z0-9_])", function(c) return string.format("%%%02x", string.byte(c)) end)
else
return nil
end
end
--16进制转换为字符串
function hex2str(hex)
local str = "";
for i = 1, string.len(hex) do
local charcode = tonumber(string.byte(hex, i, i));
str = str .. string.format("%02X", charcode);
end
return str;
end
function httpPostParamReader()
-- read post data
--server中使用lua_need_request_body on; 或者在location lua代码块中使用 ngx.req.read_body(),日志中能获取$request_body
ngx.req.read_body()
local data = ngx.req.get_body_data()
if data == nil then
printCaptureResult(-10000)
--return
end
data = ngx.unescape_uri(data)
--ngx.log(ngx.NOTICE,"data:"..data);
local contentType = ngx.req.get_headers()["content-type"] ;
local postData = nil;
local resCode = nil;
if contentType and string.find(contentType,"application/json") then
--json reader
--ngx.log(ngx.INFO,data);
local ret,backData=pcall(parseJson,data);
if ret then
postData = backData;
else
printCaptureResult(-1006)
--ngx.location.capture("/httpStatusRewrite?apiRespCodeParam=-1006");
--ngx.say("{\"resCode\":\"-1006\",\"resMsg\":\"参数格式异常.\"}");
end
else
-- array reader
--demo :method=method=placeReservedOrder&openId=MACS&appId=7982088765&format=json&sign=7bb98a054081b48f404b0c5a3786d3d90ae95327&requestParam={"BRANCH":"3089","DIRECTION":"0","DUEDATE":"2017-07-11","F_OP_SRC":"X","HD_ID":"39737FD2-B467-4581-B322-561404F504D5","MAC_ADDR":"","MARKET":"00","ORDER_MODE":"3","PRICE":"0","QTY":"100","SECURITIESNAME":"平安银行","SECU_ACC":"0199171787","SECU_CODE":"000001","SECU_NAME":"","SERVERID":"10.25.175.117","STATE":"","TRD_ID":"0B","TRD_TERMCODE":"13433445656","USER_CODE":"150129599"}×tamp=2017-07-11 18:54:37
local code,backData = readGetTypeParam(data);
if code then
postData = backData;
else
printCaptureResult(-1006)
--ngx.location.capture("/httpStatusRewrite?apiRespCodeParam=-1006");
--ngx.say("{\"resCode\":\"-1006\",\"resMsg\":\"参数格式异常.\"}");
end
end
return postData;
end
function endwith(str, substr)
if str == nil or substr == nil then
return nil, "the string or the sub-string parameter is nil"
end
str_tmp = string.reverse(str)
substr_tmp = string.reverse(substr)
if string.find(str_tmp, substr_tmp) ~= 1 then
return false
else
return true
end
end
--切割字符串,返回字符串数组
function strSplit(delimeter, str)
local find, sub, insert = string.find, string.sub, table.insert
local res = {}
local start, start_pos, end_pos = 1, 1, 1
while true do
start_pos, end_pos = find(str, delimeter, start, true)
if not start_pos then
break
end
insert(res, sub(str, start, start_pos - 1))
start = end_pos + 1
end
insert(res, sub(str,start))
return res
end
--desensitizeStr 备份,调用在log.lua中
function desensitizeStr(source,desensitizeKeyArray)
for i=1,#desensitizeKeyArray do
local regex = "(%A*)"..desensitizeKeyArray[i].."(%D*)".."(%d+)"
local m = string.match(source, regex)
if m then
--source = string.gsub(source,regex,replaceStr(%5))
source = string.gsub(source,regex,"%1"..desensitizeKeyArray[i].."%2".."***")
--print("source:"..source)
return source
--break
end
end
end
function apiMapping.getCompSign()
local request_method = ngx.var.request_method
--获取参数的值
if "GET" == request_method then
--ngx.header.content_type = "application/json";
printCaptureResult(-1013)
end
local postBody = httpPostParamReader();
if postBody then
--ngx.say("ngx.var.uri:"..ngx.var.uri);
local reqUri = ngx.var.uri;
if endwith(reqUri,"/") then
reqUri = string.sub(reqUri,1,string.len(reqUri)-1)
end
local apiSign = nil;
if(string.find(reqUri, "/AuthApp/")==1) then
reqUri = string.sub(reqUri,9);
ngx.var.reSetReqUri = string.sub(ngx.var.reSetReqUri,9);
end
if(string.find(reqUri, "/file/")==1) then
apiSign = string.gsub(string.sub(reqUri,7),"/","_") ;
else
local apiSignArr = strSplit("/",reqUri);
if #apiSignArr > 4 then
--ngx.log(ngx.ERR,"apiSignArr:"..#apiSignArr.." if apiSignArr.len >4 then not get request_body’s method");
apiSign = string.gsub(string.sub(reqUri,10),"/","_") ;
else
--ngx.say("apiSign:"..apiSign);
apiSign = string.gsub(string.sub(reqUri,10),"/","_") ;
local head = postBody["head"];
if(head ==nil) then
printCaptureResult(-1006)
end
local method = head["method"];
--ngx.say("method:"..cjson.encode(postBody));
if method and string.match(method,"%s*(.-)%s*$") ~= "" then
if not endwith(apiSign,"_"..method) then
apiSign = apiSign.."_" .. string.match(method,"%s*(.-)%s*$");
end
end
end
--ngx.log(ngx.ERR,"apiSign:"..apiSign);
--ngx.say("apiSign:"..apiSign);
local apiMappingConf = ngx.shared.apiMappingShared
--local res = apiMappingConf:get(apiSign)
--local res = routeLocation(apiSign)
local resTable = {}
local res = nil;
local redisResultJson = nil;
local localApiMappingJson = nil;
--local localApiMappingJson = apiMappingConf:get("forward_sbtpsboa_queryIPOsOrderInfo");
--local localApiMappingJsonComSign = cjson.decode(localApiMappingJson)["comSign"];
--ngx.log(ngx.ERR,"localApiMappingJsonComSign.apiSign is :"..localApiMappingJsonComSign);
--("forward_sbtpsboa_queryIPOsOrderInfo")
--redisResultJson = getRedisClusterCompSign(apiSign);--返回一个json串
local redisSwitch = ngx.shared.redisSwitchShared;
local redisSwitchFlag =redisSwitch:get("redisSwitch")
if redisSwitchFlag == "true" then
local ret,backData = pcall(getRedisClusterCompSign,apiSign);
if ret then
redisResultJson = backData;
--ngx.log(ngx.NOTICE,"redisResultJson is :"..redisResultJson);
else
ngx.log(ngx.ERR,"获取redis缓存数据失败!");
end
end
if redisSwitchFlag == "true" and redisResultJson == nil then
ngx.log(ngx.ERR,"查询缓存失败返回为空 !apiSign :"..apiSign);
end
--ngx.log(ngx.NOTICE,"redisResultJson is :"..redisResultJson);
--redisResultJson = nil;--测试读取本地
if redisResultJson ~= nil then
ngx.var.redisResultJson = redisResultJson;
--ngx.log(ngx.NOTICE,"ngx.var.redisResultJson is :"..ngx.var.redisResultJson);
if cjson.decode(redisResultJson) ~= nil then
resTable = cjson.decode(redisResultJson)--返回一个json串转为table
else
ngx.log(ngx.ERR,"redis 数据格式错误! ", err)
return
end
else--redis返回为空,做兜底操作(apiMapping.json)
--local openId = postBody["openId"];
--if openId then
-- apiSign = openId.."_"..apiSign.."_" .. string.match(openId,"%s*(.-)%s*$");
--end
localApiMappingJson = apiMappingConf:get(apiSign)
--ngx.log(ngx.ERR,"localApiMappingJson is :"..localApiMappingJson);
if localApiMappingJson == nil then
ngx.log(ngx.ERR,"undefined api sign is :"..apiSign);
printCaptureResult(-10201)
end
ngx.var.redisResultJson = localApiMappingJson;
if cjson.decode(localApiMappingJson) ~= nil then--返回一个json串转为table
local resTableTemp = cjson.decode(localApiMappingJson);
if type(resTableTemp)=="string" then
resTable = cjson.decode(resTableTemp)
end
if type(resTableTemp)=="table" then
resTable = resTableTemp
end
else
ngx.log(ngx.ERR,"this localApiMappingJson api sign has not set", err)
return
end
end
if next(resTable) ~= nil then
--ngx.log(ngx.INFO,"resTable.comSign is :"..resTable["comSign"])
res = resTable["comSign"]
end
--ngx.log(ngx.ERR,"apiSign is :"..apiSign);
ngx.var.apiSign = apiSign;
if res and res ~= nil then
ngx.var.comp_sign = res;
--ngx.say("res:"..res);
else
ngx.log(ngx.ERR,"undefined api sign is :"..apiSign);
--ngx.say("res:"..apiSign);
--ngx.exit(ngx.HTTP_OK)
printCaptureResult(-10201)
end
end
end
end
return apiMapping;
logout.lualogout = {};
function desensitizeStr(source,desensitizeKeyArray)--string,table
if source == nil or source == "" then
return nil
end
if desensitizeKeyArray == nil or desensitizeKeyArray == "" then
return source
end
for i=1,#desensitizeKeyArray do
local regex = "(%A*)"..desensitizeKeyArray[i].."(%D*)".."(%d+)"
local m = string.match(source, regex)
if m then
--source = string.gsub(source,regex,replaceStr(%5))
source = string.gsub(source,regex,"%1"..desensitizeKeyArray[i].."%2".."***")
--print("source:"..source)
return source
--break
end
end
return source--执行到这里表示没有一次做string.gsub(没有一次做正则替换)
end
--ngx.log(ngx.NOTICE,"request_body is :"..ngx.var.request_body)
--local source = "pwd\":\"12333123ad\"}\"apwd\":\"1233sd3123\"pwd:123321,adpwd1233fgfsdgs"
function parseJson(jsonString)
if jsonString then
--local cjson = require "cjson"
--parse json
local data= cjson.decode(jsonString);
--ngx.say(data["appId"])
return data;
else
return nil;
end
end
-- 删除table中的元素
function removeElementByKey(sourceJson,key)
if sourceJson == nil then
return nil
end
if key == nil then
return sourceJson
end
local tempTable = nil;
local ret,backData=pcall(parseJson,sourceJson);
if ret then
tempTable = backData;
else
--处理请求和响应信息中的超大字段request_body&resp_body
--ngx.log(ngx.ERR,"{\"resCode\":\"-1007\",\"resMsg\":\"json转换失败或者数据量过大无法转换成json\"}");
return "{\"desc\":\"big_request_shortcut\"}"
end
if tempTable == nil then
return nil
end
--新建一个临时的table
local tmp ={}
--把每个key做一个下标,保存到临时的table中,转换成{1=a,2=c,3=b}
--组成一个有顺序的table,才能在while循环准备时使用#table
for i in pairs(tempTable) do
table.insert(tmp,i)
end
local newTbl = {}
--使用while循环剔除不需要的元素
local i = 1
while i <= #tmp do
local val = tmp [i]
if val == key then
--如果是需要剔除则remove
table.remove(tmp,i)
else
--如果不是剔除,放入新的tabl中
newTbl[val] = tempTable[val]
i = i + 1
end
end
return cjson.encode(newTbl)
--return newTbl
end
function replaceJson(jsonString,replaceKey,replaceValue)
if jsonString == nil or jsonString == "" then
return "{\"resCode\":\"-499\",\"resMsg\":\"Client Closed Request\"}";
end
if replaceKey == nil or replaceValue == nil then
return jsonString
end
local tempTable = nil;
local ret,backData=pcall(parseJson,jsonString);
if ret then
tempTable = backData;
else
ngx.log(ngx.ERR,"{\"resCode\":\"-1006\",\"resMsg\":\"参数格式异常。\"}");
end
if tempTable == nil then
return nil
end
if tempTable[replaceKey] == nil then
return jsonString
end
--处理请求和响应信息中的超大字段request_body&resp_body
if ngx.var.apiSign == "forward_soas_uploadIdImg" and replaceKey == "request_body" then
tempTable[replaceKey] = "{\"desc\":\"big_request_shortcut\"}"
else
tempTable[replaceKey] = replaceValue
end
return cjson.encode(tempTable)
--return jsonString
end
function getJsonValueToTable(jsonString,stringKey)--返回table
if jsonString == nil or jsonString == "" then
return nil
end
if stringKey == nil then
return jsonString
end
local tempTable = nil;
local ret,backData=pcall(parseJson,jsonString);
if ret then
tempTable = backData;
else
--printCaptureResult(-1006)
--ngx.location.capture("/httpStatusRewrite?apiRespCodeParam=-1006");
ngx.log(ngx.ERR,"{\"resCode\":\"-1006\",\"resMsg\":\"参数格式异常。\"}");
return nil
end
if type(tempTable)=="string" then
local ret,backData=pcall(parseJson,tempTable);
if ret then
tempTable = backData;
else
ngx.log(ngx.ERR,"{\"resCode\":\"-1006\",\"resMsg\":\"参数格式异常。\"}");
return nil
end
end
if tempTable == nil then
return nil
end
if tempTable[stringKey] == nil then
return nil
end
if type(tempTable[stringKey]) =="string" then
local ret,backData=pcall(parseJson,tempTable[stringKey]);
if ret then
return backData;
else
ngx.log(ngx.ERR,"{\"resCode\":\"-1006\",\"resMsg\":\"参数格式异常。\"}");
return nil
end
end
if type(tempTable[stringKey]) =="table" then
return tempTable[stringKey]
end
end
if(ngx.var.uri ~= "/metrics") then
local host = ngx.var.host:gsub("^www.", "")
local upstream_addr = ngx.var.upstream_addr
if(upstream_addr == nil or upstream_addr == "") then
upstream_addr = "localhost"
end
metric_requests:inc(1, {host, upstream_addr, ngx.var.status})
metric_latency:observe(ngx.now() - ngx.req.start_time(), {upstream_addr})
metric_bytes:observe(tonumber(ngx.var.bytes_sent)/1024,{upstream_addr})
end
function logout.run()
local source = ngx.unescape_uri(ngx.var.request_body)--获取到request_body的字符串
--local responseSrc = ngx.var.resp_body--获取到resp_body的字符串
local responseDesc = removeElementByKey(ngx.var.resp_body,"resBody")
--ngx.log(ngx.NOTICE,"responseDesc is :"..responseDesc)
--ngx.log(ngx.NOTICE,"redisResultJson is :"..ngx.var.redisResultJson)
local desensitizeKeyArray = getJsonValueToTable(ngx.var.redisResultJson,"desensitizeKeyArray")--获取到desensitizeKeyArray的table
source = desensitizeStr(source,desensitizeKeyArray)--替换后的request_body字符串
--ngx.log(ngx.NOTICE,"source is :"..source)
--ngx.log(ngx.NOTICE,"before replace resp_map is :"..ngx.var.resp_map)
ngx.var.resp_map = replaceJson(ngx.var.resp_map,"request_body",source)
ngx.var.resp_map = replaceJson(ngx.var.resp_map,"resp_body",responseDesc)
--ngx.log(ngx.NOTICE,"after replace resp_map is :"..ngx.var.resp_map)
ngx.log(ngx.NOTICE,"resp_map"..ngx.var.resp_map)
end
return logout;
prometheus.lua-- vim: ts=2:sw=2:sts=2:expandtab
--
-- This module uses a single dictionary shared between Nginx workers to keep
-- all metrics. Each counter is stored as a separate entry in that dictionary,
-- which allows us to increment them using built-in `incr` method.
--
-- Prometheus requires that (a) all samples for a given metric are presented
-- as one uninterrupted group, and (b) buckets of a histogram appear in
-- increasing numerical order. We satisfy that by carefully constructing full
-- metric names (i.e. metric name along with all labels) so that they meet
-- those requirements while being sorted alphabetically. In particular:
--
-- * all labels for a given metric are presented in reproducible order (the one
-- used when labels were declared). "le" label for histogram metrics always
-- goes last;
-- * bucket boundaries (which are exposed as values of the "le" label) are
-- presented as floating point numbers with leading and trailing zeroes.
-- Number of of zeroes is determined for each bucketer automatically based on
-- bucket boundaries;
-- * internally "+Inf" bucket is stored as "Inf" (to make it appear after
-- all numeric buckets), and gets replaced by "+Inf" just before we
-- expose the metrics.
--
-- For example, if you define your bucket boundaries as {0.00005, 10, 1000}
-- then we will keep the following samples for a metric `m1` with label
-- `site` set to `site1`:
--
-- m1_bucket{site="site1",le="0000.00005"}
-- m1_bucket{site="site1",le="0010.00000"}
-- m1_bucket{site="site1",le="1000.00000"}
-- m1_bucket{site="site1",le="Inf"}
-- m1_count{site="site1"}
-- m1_sum{site="site1"}
--
-- "Inf" will be replaced by "+Inf" while publishing metrics.
--
-- You can find the latest version and documentation at
-- https://github.com/knyar/nginx-lua-prometheus
-- Released under MIT license.
-- Default set of latency buckets, 5ms to 10s:
local DEFAULT_BUCKETS = {0.005, 0.01, 0.02, 0.03, 0.05, 0.075, 0.1, 0.2, 0.3,
0.4, 0.5, 0.75, 1, 1.5, 2, 3, 4, 5, 10}
-- Metric is a "parent class" for all metrics.
local Metric = {}
function Metric:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
-- Checks that the right number of labels values have been passed.
--
-- Args:
-- label_values: an array of label values.
--
-- Returns:
-- an error message or nil
function Metric:check_label_values(label_values)
if self.label_names == nil and label_values == nil then
return
elseif self.label_names == nil and label_values ~= nil then
return "Expected no labels for " .. self.name .. ", got " .. #label_values
elseif label_values == nil and self.label_names ~= nil then
return "Expected " .. #self.label_names .. " labels for " ..
self.name .. ", got none"
elseif #self.label_names ~= #label_values then
return "Wrong number of labels for " .. self.name .. ". Expected " ..
#self.label_names .. ", got " .. #label_values
else
for i, k in ipairs(self.label_names) do
if label_values[i] == nil then
return "Unexpected nil value for label " .. k .. " of " .. self.name
end
end
end
end
local Counter = Metric:new()
-- Increase a given counter by `value`
--
-- Args:
-- value: (number) a value to add to the counter. Defaults to 1 if skipped.
-- label_values: an array of label values. Can be nil (i.e. not defined) for
-- metrics that have no labels.
function Counter:inc(value, label_values)
local err = self:check_label_values(label_values)
if err ~= nil then
self.prometheus:log_error(err)
return
end
self.prometheus:inc(self.name, self.label_names, label_values, value or 1)
end
local Gauge = Metric:new()
-- Set a given gauge to `value`
--
-- Args:
-- value: (number) a value to set the gauge to. Should be defined.
-- label_values: an array of label values. Can be nil (i.e. not defined) for
-- metrics that have no labels.
function Gauge:set(value, label_values)
if value == nil then
self.prometheus:log_error("No value passed for " .. self.name)
return
end
local err = self:check_label_values(label_values)
if err ~= nil then
self.prometheus:log_error(err)
return
end
self.prometheus:set(self.name, self.label_names, label_values, value)
end
local Histogram = Metric:new()
-- Record a given value in a histogram.
--
-- Args:
-- value: (number) a value to record. Should be defined.
-- label_values: an array of label values. Can be nil (i.e. not defined) for
-- metrics that have no labels.
function Histogram:observe(value, label_values)
if value == nil then
self.prometheus:log_error("No value passed for " .. self.name)
return
end
local err = self:check_label_values(label_values)
if err ~= nil then
self.prometheus:log_error(err)
return
end
self.prometheus:histogram_observe(self.name, self.label_names, label_values, value)
end
local Prometheus = {}
Prometheus.__index = Prometheus
Prometheus.initialized = false
-- Generate full metric name that includes all labels.
--
-- Args:
-- name: string
-- label_names: (array) a list of label keys.
-- label_values: (array) a list of label values.
-- Returns:
-- (string) full metric name.
local function full_metric_name(name, label_names, label_values)
if not label_names then
return name
end
local label_parts = {}
for idx, key in ipairs(label_names) do
local label_value = (string.format("%s", label_values[idx])
:gsub("[^\032-\126]", "") -- strip non-printable characters
:gsub("\\", "\\\\")
:gsub('"', '\\"'))
table.insert(label_parts, key .. '="' .. label_value .. '"')
end
return name .. "{" .. table.concat(label_parts, ",") .. "}"
end
-- Construct bucket format for a list of buckets.
--
-- This receives a list of buckets and returns a sprintf template that should
-- be used for bucket boundaries to make them come in increasing order when
-- sorted alphabetically.
--
-- To re-phrase, this is where we detect how many leading and trailing zeros we
-- need.
--
-- Args:
-- buckets: a list of buckets
--
-- Returns:
-- (string) a sprintf template.
local function construct_bucket_format(buckets)
local max_order = 1
local max_precision = 1
for _, bucket in ipairs(buckets) do
assert(type(bucket) == "number", "bucket boundaries should be numeric")
-- floating point number with all trailing zeros removed
local as_string = string.format("%f", bucket):gsub("0*$", "")
local dot_idx = as_string:find(".", 1, true)
max_order = math.max(max_order, dot_idx - 1)
max_precision = math.max(max_precision, as_string:len() - dot_idx)
end
return "%0" .. (max_order + max_precision + 1) .. "." .. max_precision .. "f"
end
-- Extract short metric name from the full one.
--
-- Args:
-- full_name: (string) full metric name that can include labels.
--
-- Returns:
-- (string) short metric name with no labels. For a `*_bucket` metric of
-- histogram the _bucket suffix will be removed.
local function short_metric_name(full_name)
local labels_start, _ = full_name:find("{")
if not labels_start then
-- no labels
return full_name
end
local suffix_idx, _ = full_name:find("_bucket{")
if suffix_idx and full_name:find("le=") then
-- this is a histogram metric
return full_name:sub(1, suffix_idx - 1)
end
-- this is not a histogram metric
return full_name:sub(1, labels_start - 1)
end
-- Makes a shallow copy of a table
local function copy_table(table)
local new = {}
if table ~= nil then
for k, v in ipairs(table) do
new[k] = v
end
end
return new
end
-- Check metric name and label names for correctness.
--
-- Regular expressions to validate metric and label names are
-- documented in https://prometheus.io/docs/concepts/data_model/
--
-- Args:
-- metric_name: (string) metric name.
-- label_names: label names (array of strings).
--
-- Returns:
-- Either an error string, or nil of no errors were found.
local function check_metric_and_label_names(metric_name, label_names)
if not metric_name:match("^[a-zA-Z_:][a-zA-Z0-9_:]*$") then
return "Metric name '" .. metric_name ..
"' contains invalid characters"
end
for _, label_name in ipairs(label_names or {}) do
if label_name == "le" then
return "Invalid label name 'le' in " .. metric_name
end
if not label_name:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
return "Metric '" .. metric_name .. "' label name '" .. label_name ..
"' contains invalid characters"
end
end
end
-- Initialize the module.
--
-- This should be called once from the `init_by_lua` section in nginx
-- configuration.
--
-- Args:
-- dict_name: (string) name of the nginx shared dictionary which will be
-- used to store all metrics
-- prefix: (optional string) if supplied, prefix is added to all
-- metric names on output
--
-- Returns:
-- an object that should be used to register metrics.
function Prometheus.init(dict_name, prefix)
local self = setmetatable({}, Prometheus)
self.dict = ngx.shared[dict_name or "prometheus_metrics"]
self.help = {}
if prefix then
self.prefix = prefix
else
self.prefix = ''
end
self.type = {}
self.registered = {}
self.buckets = {}
self.bucket_format = {}
self.initialized = true
self:counter("nginx_metric_errors_total",
"Number of nginx-lua-prometheus errors")
self.dict:set("nginx_metric_errors_total", 0)
return self
end
function Prometheus:log_error(...)
ngx.log(ngx.ERR, ...)
self.dict:incr("nginx_metric_errors_total", 1)
end
function Prometheus:log_error_kv(key, value, err)
self:log_error(
"Error while setting '", key, "' to '", value, "': '", err, "'")
end
-- Register a counter.
--
-- Args:
-- name: (string) name of the metric. Required.
-- description: (string) description of the metric. Will be used for the HELP
-- comment on the metrics page. Optional.
-- label_names: array of strings, defining a list of metrics. Optional.
--
-- Returns:
-- a Counter object.
function Prometheus:counter(name, description, label_names)
if not self.initialized then
ngx.log(ngx.ERR, "Prometheus module has not been initialized")
return
end
local err = check_metric_and_label_names(name, label_names)
if err ~= nil then
self:log_error(err)
return
end
if self.registered[name] then
self:log_error("Duplicate metric " .. name)
return
end
self.registered[name] = true
self.help[name] = description
self.type[name] = "counter"
return Counter:new{name=name, label_names=label_names, prometheus=self}
end
-- Register a gauge.
--
-- Args:
-- name: (string) name of the metric. Required.
-- description: (string) description of the metric. Will be used for the HELP
-- comment on the metrics page. Optional.
-- label_names: array of strings, defining a list of metrics. Optional.
--
-- Returns:
-- a Gauge object.
function Prometheus:gauge(name, description, label_names)
if not self.initialized then
ngx.log(ngx.ERR, "Prometheus module has not been initialized")
return
end
local err = check_metric_and_label_names(name, label_names)
if err ~= nil then
self:log_error(err)
return
end
if self.registered[name] then
self:log_error("Duplicate metric " .. name)
return
end
self.registered[name] = true
self.help[name] = description
self.type[name] = "gauge"
return Gauge:new{name=name, label_names=label_names, prometheus=self}
end
-- Register a histogram.
--
-- Args:
-- name: (string) name of the metric. Required.
-- description: (string) description of the metric. Will be used for the HELP
-- comment on the metrics page. Optional.
-- label_names: array of strings, defining a list of metrics. Optional.
-- buckets: array if numbers, defining bucket boundaries. Optional.
--
-- Returns:
-- a Histogram object.
function Prometheus:histogram(name, description, label_names, buckets)
if not self.initialized then
ngx.log(ngx.ERR, "Prometheus module has not been initialized")
return
end
local err = check_metric_and_label_names(name, label_names)
if err ~= nil then
self:log_error(err)
return
end
for _, suffix in ipairs({"", "_bucket", "_count", "_sum"}) do
if self.registered[name .. suffix] then
self:log_error("Duplicate metric " .. name .. suffix)
return
end
self.registered[name .. suffix] = true
end
self.help[name] = description
self.type[name] = "histogram"
self.buckets[name] = buckets or DEFAULT_BUCKETS
self.bucket_format[name] = construct_bucket_format(self.buckets[name])
return Histogram:new{name=name, label_names=label_names, prometheus=self}
end
-- Set a given dictionary key.
-- This overwrites existing values, so it should only be used when initializing
-- metrics or when explicitely overwriting the previous value of a metric.
function Prometheus:set_key(key, value)
local ok, err = self.dict:safe_set(key, value)
if not ok then
self:log_error_kv(key, value, err)
end
end
-- Increment a given counter by `value`.
--
-- Args:
-- name: (string) short metric name without any labels.
-- label_names: (array) a list of label keys.
-- label_values: (array) a list of label values.
-- value: (number) value to add. Optional, defaults to 1.
function Prometheus:inc(name, label_names, label_values, value)
local key = full_metric_name(name, label_names, label_values)
if value == nil then value = 1 end
if value < 0 then
self:log_error_kv(key, value, "Value should not be negative")
return
end
local newval, err = self.dict:incr(key, value)
if newval then
return
end
-- Yes, this looks like a race, so I guess we might under-report some values
-- when multiple workers simultaneously try to create the same metric.
-- Hopefully this does not happen too often (shared dictionary does not get
-- reset during configuation reload).
if err == "not found" then
self:set_key(key, value)
return
end
-- Unexpected error
self:log_error_kv(key, value, err)
end
-- Set the current value of a gauge to `value`
--
-- Args:
-- name: (string) short metric name without any labels.
-- label_names: (array) a list of label keys.
-- label_values: (array) a list of label values.
-- value: (number) the new value for the gauge.
function Prometheus:set(name, label_names, label_values, value)
local key = full_metric_name(name, label_names, label_values)
self:set_key(key, value)
end
-- Record a given value into a histogram metric.
--
-- Args:
-- name: (string) short metric name without any labels.
-- label_names: (array) a list of label keys.
-- label_values: (array) a list of label values.
-- value: (number) value to observe.
function Prometheus:histogram_observe(name, label_names, label_values, value)
self:inc(name .. "_count", label_names, label_values, 1)
self:inc(name .. "_sum", label_names, label_values, value)
-- we are going to mutate arrays of label names and values, so create a copy.
local l_names = copy_table(label_names)
local l_values = copy_table(label_values)
-- Last bucket. Note, that the label value is "Inf" rather than "+Inf"
-- required by Prometheus. This is necessary for this bucket to be the last
-- one when all metrics are lexicographically sorted. "Inf" will get replaced
-- by "+Inf" in Prometheus:collect().
table.insert(l_names, "le")
table.insert(l_values, "Inf")
self:inc(name .. "_bucket", l_names, l_values, 1)
local label_count = #l_names
for _, bucket in ipairs(self.buckets[name]) do
if value <= bucket then
-- last label is now "le"
l_values[label_count] = self.bucket_format[name]:format(bucket)
self:inc(name .. "_bucket", l_names, l_values, 1)
end
end
end
-- Present all metrics in a text format compatible with Prometheus.
--
-- This function should be used to expose the metrics on a separate HTTP page.
-- It will get the metrics from the dictionary, sort them, and expose them
-- aling with TYPE and HELP comments.
function Prometheus:collect()
ngx.header.content_type = "text/plain"
if not self.initialized then
ngx.log(ngx.ERR, "Prometheus module has not been initialized")
return
end
local keys = self.dict:get_keys(0)
-- Prometheus server expects buckets of a histogram to appear in increasing
-- numerical order of their label values.
table.sort(keys)
local seen_metrics = {}
for _, key in ipairs(keys) do
local value, err = self.dict:get(key)
if value then
local short_name = short_metric_name(key)
if not seen_metrics[short_name] then
if self.help[short_name] then
ngx.say("# HELP " .. self.prefix .. short_name .. " " .. self.help[short_name])
end
if self.type[short_name] then
ngx.say("# TYPE " .. self.prefix .. short_name .. " " .. self.type[short_name])
end
seen_metrics[short_name] = true
end
-- Replace "Inf" with "+Inf" in each metric's last bucket 'le' label.
ngx.say(self.prefix .. key:gsub('le="Inf"', 'le="+Inf"'), " ", value)
else
self:log_error("Error getting '", key, "': ", err)
end
end
end
return Prometheus
request.luarequest = {};
function request.run()
local resp_body = string.sub(ngx.arg[1], 1, 1000)
ngx.ctx.buffered = (ngx.ctx.buffered or"") .. resp_body
if ngx.arg[2] then
ngx.var.resp_body = ngx.ctx.buffered
local map = {}
map["logTraceId"] = ngx.var.request_id;
map["remote_addr"] = ngx.var.remote_addr;
map["remote_user"] = ngx.var.remote_user;
map["time_local"] = ngx.unescape_uri(ngx.var.time_local);
map["request_method"] = ngx.var.request_method;
map["apiSign"] = ngx.var.apiSign;
map["comp_sign"] = ngx.var.comp_sign;
map["request"] = ngx.unescape_uri(ngx.var.request);
map["status"] = ngx.var.status;
map["body_bytes_sent"] = ngx.var.body_bytes_sent;
map["http_referer"] = ngx.var.http_referer;
map["http_user_agent"] = ngx.var.http_user_agent;
map["http_x_forwarded_for"] = ngx.var.http_x_forwarded_for;
map["request_body"] = ngx.unescape_uri(ngx.var.request_body);
map["resp_body"] = ngx.unescape_uri(ngx.var.resp_body);
map["upstream_addr"] = ngx.var.upstream_addr;
map["bytes_sent"] = ngx.var.bytes_sent;
map["request_length"] = ngx.var.request_length;
map["upstream_response_time"] = ngx.var.upstream_response_time;
map["request_time"] = ngx.var.request_time;
ngx.var.resp_map = cjson.encode(map);
end
end
return request;
upstreamdynamic.luaupstreamdynamic = {};
function upstreamdynamic.init()
--upstream = require "ngx.upstream"
--get_servers = upstream.get_servers
--get_upstreams = upstream.get_upstreams
--us = get_upstreams()
local upstreamShared = ngx.shared.upstreamShared;
upstreamShared:flush_all();
upstreamFile = SCRIPT_ROOT_PATH.."../../servers/upstream.com";
local file = io.open(upstreamFile, "r");
local data = file:read("*all");
upstreamToShared(data);
end
function upstreamToShared(data)
local upstreamShared = ngx.shared.upstreamShared;
--ngx.log(ngx.ERR,"data:"..data);
local tableTemp = strSplit("\n", data);
--ngx.log(ngx.ERR,"tableTemp:"..cjson.encode(tableTemp));
local value = "";
local key = "";
local flag = true;
for _, temp in ipairs(tableTemp) do
if flag then
flag = false;
if string.find(temp,"upstream") then
local i,j = string.find(temp,"upstream");
key = trim(string.sub(temp,j+1, string.len(temp)));
end
else
if string.find(temp,"upstream") then
local i,j = string.find(temp,"upstream");
key = trim(string.sub(temp,j+1, string.len(temp)));
elseif string.find(temp,"{") then
value= value..trim(temp).."\n";
elseif string.find(temp,";") then
value= value..trim(temp).."\n";
elseif string.find(temp,"}") then
value= value..trim(temp);
--ngx.log(ngx.ERR,"key:"..key.."||".."value:"..value);
upstreamShared:set(key,value);
--ngx.log(ngx.ERR,"upstreamShared.get."..key..":"..upstreamShared:get(key));
value = "";
flag = true;
else
value= value..trim(temp);
end
end
end
end
function line_break_format(data)--shard按换行符切割\n
--ngx.log(ngx.ERR,"data :"..data);
local dataTemp = nil;
if endwith(data,"\n") then
data = string.sub(data,1,string.len(data)-1)
end
dataTemp = strSplit("\n",data);
--ngx.log(ngx.ERR,"dataTemp :"..cjson.encode(dataTemp));
return dataTemp;
end
function semi_colon_format(data)--request_body按分号切割;
--ngx.log(ngx.ERR,"data :"..data);
local dataTemp = nil;
if endwith(data,";") then
data = string.sub(data,1,string.len(data)-1)
dataTemp = strSplit(";",data);
else
ngx.say("格式检查错误,必须已分号结尾!")
return
end
--ngx.log(ngx.ERR,"dataTemp :"..cjson.encode(dataTemp));
return dataTemp;
end
function reconstruction_nginx_upstreamDetails(data)
--ngx.log(ngx.ERR,"reconstruction_nginx_upstreamDetails.data:"..data);
local dataTemp = strSplit("\n",data);
--ngx.log(ngx.ERR,"tableTemp:"..cjson.encode(dataTemp));
local upstreamStr_ip_hash = "";
local upstreamStr_keepalive = "";
local upstreamStr_backup = "";
local upstreamStr_down = "";
local upstreamStr = "";
local upstreamName = "";
local upstreamBraceL = "";
local upstreamBraceR = "";
local upstreamServerTemp = "";
local flag = true;
for _, temp in ipairs(dataTemp) do
--ngx.log(ngx.ERR,"reconstruction_nginx_upstreamDetails.tableTemp.temp:"..temp);
if flag then
flag = false;
if string.find(temp,"upstream") then
local i,j = string.find(temp,"upstream");
upstreamName = "upstream ".. trim(string.sub(temp,j+1, string.len(temp))).."\n";
local upstreamSharedValue = getUpstreamFromShared(trim(string.sub(temp,j+1, string.len(temp))));
local upstreamSharedTemp = line_break_format(upstreamSharedValue)
for _, temp in ipairs(upstreamSharedTemp) do--shared里面是按分号结尾,换行
if string.find(temp,"ip_hash") then
local i,j = string.find(temp,"ip_hash");
upstreamStr_ip_hash = upstreamStr_ip_hash.." "..trim(string.sub(temp,i, string.len(temp))).."\n";
end
if string.find(temp,"keepalive") then
local i,j = string.find(temp,"keepalive");
upstreamStr_keepalive = upstreamStr_keepalive.." "..trim(string.sub(temp,i, string.len(temp))).."\n";
end
end
end
else
if string.find(temp,"upstream") then
local i,j = string.find(temp,"upstream");
upstreamName = "upstream ".. trim(string.sub(temp,j+1, string.len(temp))).."\n";
elseif string.find(temp,"{") then
upstreamBraceL = upstreamBraceL..trim(temp).."\n";
elseif string.find(temp,"}") then
upstreamBraceR = upstreamBraceR..trim(temp).."\n";
--ngx.log(ngx.ERR,"reconstruction_nginx_upstreamDetails.upstreamTemp:"..upstreamTemp);
upstreamStr = upstreamStr..upstreamName..upstreamBraceL..upstreamServerTemp..upstreamStr_ip_hash..upstreamStr_keepalive..upstreamBraceR;
------重置-----
upstreamBraceR = "";
upstreamBraceL = "";
upstreamServerTemp = "";
upstreamStr_ip_hash = "";
upstreamStr_keepalive = "";
flag = true;
elseif string.find(temp,"server") then
if string.find(temp,"backup=1 down=0") then
local i,j = string.find(temp,"backup=1 down=0");--backup 和down同时只生效一个
upstreamServerTemp = upstreamServerTemp.." "..trim(string.sub(temp,1,i-1)).." backup;\n";--手动处理成和文件格式一样
--ngx.log(ngx.ERR,"upstreamServerTemp"..upstreamServerTemp)
end
if string.find(temp,"backup=0 down=1") then
local i,j = string.find(temp,"backup=0 down=1");
upstreamServerTemp = upstreamServerTemp.." "..trim(string.sub(temp,1,i-1)).." down;\n";
end
if string.find(temp,"backup=0 down=0") then
local i,j = string.find(temp,"backup=0 down=0");
upstreamServerTemp = upstreamServerTemp.." "..trim(string.sub(temp,1,i-1))..";\n";
end
else
upstreamServerTemp = upstreamServerTemp.."";
end
end
end
return upstreamStr;
end
--切割字符串,返回字符串数组
function strSplit(delimeter, str)
local find, sub, insert = string.find, string.sub, table.insert
local res = {}
local start, start_pos, end_pos = 1, 1, 1
while true do
start_pos, end_pos = find(str, delimeter, start, true)
if not start_pos then
break
end
insert(res, sub(str, start, start_pos - 1))
start = end_pos + 1
end
insert(res, sub(str,start))
return res
end
function trim(s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end
function parseJson(jsonString)
if jsonString then
--local cjson = require "cjson"
--parse json
local data= cjson.decode(jsonString);
--ngx.say(data["appId"])
return data;
else
return nil;
end
end
function getUpstreamFromShared(upstreamName)
local upstreamShared = ngx.shared.upstreamShared;
return upstreamShared:get(upstreamName);
end
function setUpstreamFromShared(upstreamName,upstreamValue)
local upstreamShared = ngx.shared.upstreamShared;
upstreamShared:set(upstreamName,upstreamValue);
end
function removeUpstreamFromShared(upstreamName)
local upstreamShared = ngx.shared.upstreamShared;
upstreamShared:delete(upstreamName);
end
function sharedBackupToFile()
local upstreamShared = ngx.shared.upstreamShared;
local file = io.open(upstreamFile, "w+");
local keys = upstreamShared:get_keys(100);
--ngx.log(ngx.ERR,"keys"..cjson.encode(keys));
for index, key in pairs(keys) do
local value = upstreamShared:get(key);
--ngx.log(ngx.ERR,"key:"..key.."||".."value:"..value);
file:write("upstream "..key.."\n"..value.."\n");
end
file:flush();
file:close();
end
----暂时没有用到
function upstreamDetails()
--local upstream = require "ngx.upstream"
--local get_servers = upstream.get_servers
--local get_upstreams = upstream.get_upstreams
--local us = get_upstreams()
--ngx.say("us :"..cjson.encode(us));
local upstreamStr = "";
for _, u in ipairs(us) do
--local peers = upstream.get_primary_peers(u);
--ngx.log(ngx.ERR,cjson.encode(peers));
if u == "_dyups_upstream_down_host_" then--暂时没搞明白这个是弄啥子的?
upstreamStr = upstreamStr.."";
else
local upstream = "upstream ".. u.."\n".."{".."\n";
local srvs, err = get_servers(u)
if not srvs then
ngx.say("failed to get servers in upstream ", u)
else
--ngx.say("srvs :"..cjson.encode(srvs));
for _, srv in ipairs(srvs) do
local first = true
--ngx.log(ngx.ERR,"srv :"..cjson.encode(srv));
local upstreamTemp = "";
local upstreamServer = "";
local upstreamServer_backup = "";
local upstreamServer_down = "";
local upstreamServer_weight = "";
local upstreamServer_fail_timeout = "";
local upstreamServer_max_fails = "";
for k, v in pairs(srv) do
if first then
first = false
local upstreamTemp = "";
--upstreamTemp = upstreamTemp.." ";
upstreamTemp = upstreamTemp.." ";
else
--upstreamTemp = upstreamTemp..",";
upstreamTemp = upstreamTemp.." ";
end
if type(v) == "table" then
--ngx.say("v :"..cjson.encode(v));
upstreamTemp = upstreamTemp.."{", concat(v, ", "), "}"
else
if k == "name" then
upstreamServer = upstreamServer.."server".." "..v.." "--cjson.encode(v)
elseif k == "addr" then
upstreamTemp = upstreamTemp.."";
elseif k == "ip_hash" then
ngx.log(ngx.ERR,"k:"..k.." || ".."v:"..cjson.encode(v));
upstreamTemp = upstreamTemp..k..";".."\n";
elseif k == "keepalive" then
ngx.log(ngx.ERR,"k:"..k.." || ".."v:"..cjson.encode(v));
upstreamTemp = upstreamTemp..k.." "..v..";".."\n";
elseif k == "down" then
upstreamServer_down = upstreamServer_down..k.." "
elseif k == "backup" then
upstreamServer_backup = upstreamServer_backup..k.." "
elseif k == "weight" then
upstreamServer_weight = upstreamServer_weight..k.."="..v.." "
elseif k == "fail_timeout" then
upstreamServer_fail_timeout = upstreamServer_fail_timeout..k.."="..v.." "
elseif k == "max_fails" then
upstreamServer_max_fails = upstreamServer_max_fails..k.."="..v.." "
else
upstreamTemp = upstreamTemp..k.."="..v--cjson.encode(v)
end
end
end
--upstream = upstream..upstreamServer.." "..upstreamTemp;
upstream = upstream.." "..upstreamServer..upstreamServer_weight..upstreamServer_fail_timeout..upstreamServer_max_fails..upstreamServer_down..upstreamServer_backup..";".."\n";
end
upstream = upstream.."}".."\n"
upstreamStr = upstreamStr..upstream;
end
end
end
ngx.say(upstreamStr);
--ngx.log(ngx.ERR,upstreamStr);
return upstreamStr;
end
--reconstructionType(reqest_body||memory||shared)
--reqest_body---格式是已分号(;)分割
--memory---换行符(\n)分割
--shared---换行符(\n)分割
function reconstruction_nginx_upstream(upstreamName,data,reconstructionType)
--ngx.log(ngx.ERR,"reconstruction_nginx_upstream.upstreamName :"..upstreamName);
--ngx.log(ngx.ERR,"reconstruction_nginx_upstream.data :"..data);
--ngx.log(ngx.ERR,"reconstruction_nginx_upstream.reconstructionType :"..reconstructionType);
local dataTemp = "";
--local upstreamStr = "";
local upstreamStr = "upstream ".. upstreamName.."\n".."{".."\n";
local upstream_shared_ip_hash = "";
local upstream_shared_keepalive = "";
local upstream_shared_backup = "";
local upstream_shared_down = "";
local upstreamServerTemp = "";
local upstreamSharedTemp = nil;
local upstreamSharedValue = getUpstreamFromShared(upstreamName);--获取shared当前upstreamName对应的值
if upstreamSharedValue ~= nil then
--ngx.log(ngx.ERR,"reconstruction_nginx_upstream.upstreamName.upstreamSharedValue :"..upstreamSharedValue);
upstreamSharedTemp = line_break_format(upstreamSharedValue)--切割shared尝试拿到ip_hash...
for _, temp in ipairs(upstreamSharedTemp) do--shared里面是按分号结尾,换行
--ngx.say("temp :"..temp);
if string.find(temp,"ip_hash") then
local i,j = string.find(temp,"ip_hash");
upstream_shared_ip_hash = upstream_shared_ip_hash.." "..trim(string.sub(temp,i, string.len(temp))).."\n";
end
if string.find(temp,"keepalive") then
local i,j = string.find(temp,"keepalive");
upstream_shared_keepalive = upstream_shared_keepalive.." "..trim(string.sub(temp,i, string.len(temp))).."\n";
end
end
end
--------------------------------------------------------
if reconstructionType == "reqest_body" then--请求body里面有ip_hash/keepalive;
dataTemp = semi_colon_format(data);
upstreamStr = "{".."\n";
local upstreamServerTemp = "";
local upstream_req_body_ip_hash = "";
local upstream_req_body_keepalive = "";
local upstream_req_body_backup = "";
local upstream_req_body_down = "";
--ngx.log(ngx.ERR,"dataTemp :"..cjson.encode(dataTemp));
for _, temp in ipairs(dataTemp) do
--ngx.say("temp :"..temp);
--ngx.log(ngx.ERR,"temp :"..temp);
if string.find(temp,"ip_hash") then
local i,j = string.find(temp,"ip_hash");
upstream_req_body_ip_hash = upstream_req_body_ip_hash..trim(string.sub(temp,i, string.len(temp)))..";\n";
elseif string.find(temp,"keepalive") then
local i,j = string.find(temp,"keepalive");
upstream_req_body_keepalive = upstream_req_body_keepalive..trim(string.sub(temp,i, string.len(temp)))..";\n";
else
upstreamServerTemp = upstreamServerTemp..trim(temp)..";\n";
--ngx.log(ngx.ERR,"upstreamServerTemp :"..upstreamServerTemp);
end
end
upstreamStr = upstreamStr..upstreamServerTemp..upstream_req_body_ip_hash..upstream_req_body_keepalive.."}"
--ngx.say("upstreamServerStr :"..upstreamServerStr);
--ngx.log(ngx.ERR,"upstreamServerStr :"..upstreamStr);
return upstreamStr;
end
if reconstructionType == "memory" then
dataTemp = line_break_format(data);
upstreamStr = "{".."\n";
for _, temp in ipairs(dataTemp) do
--ngx.say("temp :"..temp);
--ngx.log(ngx.ERR,"temp :"..temp);
if string.find(temp,"ip_hash") then
local i,j = string.find(temp,"ip_hash");
upstreamStr_ip_hash = upstreamStr_ip_hash..trim(string.sub(temp,i, string.len(temp)))..";\n";
elseif string.find(temp,"keepalive") then
local i,j = string.find(temp,"keepalive");
upstreamStr_keepalive = upstreamStr_keepalive..trim(string.sub(temp,i, string.len(temp)))..";\n";
else
upstreamServerTemp = upstreamServerTemp..trim(temp)..";\n";
--ngx.log(ngx.ERR,"upstreamServerTemp :"..upstreamServerTemp);
end
end
end
----------------------------------------------------
if reconstructionType == "shared" then
dataTemp = line_break_format(data);--此处data是响应信息
for _, temp in ipairs(dataTemp) do
--ngx.log(ngx.ERR,"temp :"..temp);
if string.find(temp,"server") then
if string.find(temp,"backup=1 down=0") then
local i,j = string.find(temp,"backup=1 down=0");--backup 和down同时只生效一个
upstreamServerTemp = upstreamServerTemp.." "..trim(string.sub(temp,1,i-1)).." backup;";--手动处理成和文件格式一样
elseif string.find(temp,"backup=0 down=1") then
local i,j = string.find(temp,"backup=0 down=1");
upstreamServerTemp = upstreamServerTemp.." "..trim(string.sub(temp,1,i-1)).." down;";
elseif string.find(temp,"backup=0 down=0") then
local i,j = string.find(temp,"backup=0 down=0");
upstreamServerTemp = upstreamServerTemp.." "..trim(string.sub(temp,1,i-1))..";";
else
upstreamServerTemp = upstreamServerTemp.."";
end
upstreamServerTemp = upstreamServerTemp.." \n";
end
end
--ngx.log(ngx.ERR,"upstreamServerTemp :"..upstreamServerTemp);
upstreamStr = upstreamStr..upstreamServerTemp;
end
--ngx.log(ngx.ERR,"upstream_shared_ip_hash :"..upstream_shared_ip_hash);
upstreamStr = upstreamStr..upstream_shared_ip_hash..upstream_shared_keepalive.."}".."\n";
--ngx.log(ngx.ERR,"upstreamStr :"..upstreamStr);
return upstreamStr;
end
function endwith(str, substr)
if str == nil or substr == nil then
return nil, "the string or the sub-string parameter is nil"
end
str_tmp = string.reverse(str)
substr_tmp = string.reverse(substr)
if string.find(str_tmp, substr_tmp) ~= 1 then
return false
else
return true
end
end
function upstreamdynamic.run()
local url = ngx.var.uri;
local data = ngx.req.get_body_data()
local request_method = ngx.var.request_method;
url = string.sub(url,1+1,string.len(url));
--ngx.log(ngx.ERR,"url :"..url);
local args = strSplit("/",url);
--ngx.log(ngx.ERR,"args:"..cjson.encode(args));
if #args<4 then
if request_method == "GET" then
if args[2] == "detail" then--查看全部列表信息
--ngx.log(ngx.ERR,"args[2]:"..args[2]);
local res = ngx.location.capture("/detail",{method=ngx.HTTP_GET});
if res.status ~= 200 then
ngx.say("请求有误,请检查!")
return
end
--ngx.say(res['body']);
local upstreamValue = reconstruction_nginx_upstreamDetails(res['body']);
--ngx.log(ngx.ERR,"reconstruction_nginx_upstreamDetails:"..upstreamValue);
ngx.say(upstreamValue);
end
if args[2] == "upstream" then--查看单个upstream信息
--ngx.log(ngx.ERR,"args[2]&args[3]:"..args[2]..","..args[3]);
local res = ngx.location.capture("/upstream/"..args[3],{method=ngx.HTTP_GET});
if res.status ~= 200 then
ngx.say("请求参数有误,请检查!")
return
end
--ngx.say(res['body']);
local upstreamValue = reconstruction_nginx_upstream(args[3],res['body'],"shared");
ngx.say(upstreamValue);
end
end
if request_method == "POST" then
if args[2] == "upstream" then--更新单个upstream信息
--ngx.log(ngx.ERR,"data :"..data);
--ngx.log(ngx.ERR,"args[2]&args[3]:"..args[2]..","..args[3]);
local res = ngx.location.capture("/upstream/"..args[3],{method=ngx.HTTP_POST,body=data});
if res.status ~= 200 then
ngx.say("请求参数有误,请检查!")
return
end
ngx.say(res['body']);
--local upstreamValue = getUpstreamFromShared(args[3]);
local upstreamValue = reconstruction_nginx_upstream(args[3],data,"reqest_body");
--ngx.log(ngx.ERR,"POST---------upstreamValue:"..upstreamValue);
--local upstreamValue = semi_colon_format(data);
--local upstreamSharedValue =getUpstreamFromShared(args[3]);--不管shared里面有没有,都会写shared,有就更新,没有就新增
--if upstreamValue ~= nil then
setUpstreamFromShared(args[3],upstreamValue);--注意table--cjson.encode(upstreamValue));
--end
sharedBackupToFile();
end
end
if request_method == "DELETE" then
if args[2] == "upstream" then
--ngx.log(ngx.ERR,"data :"..data);
--ngx.log(ngx.ERR,"args[2]&args[3]:"..args[2]..","..args[3]);
local res = ngx.location.capture("/upstream/"..args[3],{method=ngx.HTTP_DELETE});
if res.status ~= 200 then
ngx.say("请求参数有误,请检查!")
return
end
ngx.say(res['body']);
removeUpstreamFromShared(args[3]);--删除shared中对应的key
sharedBackupToFile();
end
end
else
ngx.log(ngx.ERR,"error for update upstream");
ngx.say("error for update upstream");
return
end
end
return upstreamdynamic;
apiMapping.json{
"forward_xjb_updateAgmt":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_queryGZTrdacct":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_queryIPOsSecuInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_soas_findByBankText":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryUserOccuInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_queryFundVol":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_historicalRevision":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kbss_signElectronicPact":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forword_kbss_getAccountByID":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_getCustIDCardImg":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_getXjbProgress":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_khpp_insertDataBatch":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_findThreeBank":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_queryCancelAccountStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_submitCustRiskAns":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_logonData":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_openQER":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_batch_collectionTbcBankInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_cyb_cybSignResultCallBack":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_listBoodsBizInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_khpp_loadData":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_getDZHOpenaccResultInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_checkShareholderAccounts":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_submitRish":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_queryAccountInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_submitLicense":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_findQuestionnaire":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_chkCust":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxpService_zpck":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryBankSecurityTrans":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_bankAuth":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_uploadIdImg":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_push_applyPush":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_bindCode":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_pledgeOrRepurchase":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_mainChangeObey":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_genSmsVerifyCode":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_queryRiskMatchLevel":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_cybAdd":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_lfexOpenAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_finaAcceptedServiceTime":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_tradingDay":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_push_changePushType":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxpService_queryFunds":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_checkRisks":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryRegisterAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_videoInvalid":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_IdCardpromotion":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_submitOpenaccInfoForBatch":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryOrder":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_appropriateInfoSave":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_entrustOrderCancel":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_bps_queryRepurchaseOffer":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sms_sendSMS":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_getCanPledgeShares":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryNewShareAcctInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_pushThs":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_ggt_isLegalClient":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_custAgmtCheck":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_getXJBAgmt":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_IdCardAuthentication":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_genSmsVerifyCode":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_openAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_bankSecurityTransOut":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryCustAdequacyInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_submitOpenaccNoMaterialInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_OpenAcc_saveHangUpVideo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_custRiskBatchAnswer":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_queryCustSource":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_aoi_ApproMatching":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_queryAssetAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_config_getIp":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_bjhgQualificationCheck":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sms_saveSms":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_queryIPOChosenInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_getTrdCustAgmt":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_querySecuMessage":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_querySecuAcc":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_khpp_delData":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_cts_queryFunds":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryFundsFlow":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_getUserQueueNo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryCustomInfoByType":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxpService_zpqk":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_ggt_getStockholderCardList":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_saveAcceptedAccountTransferInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_validateQualifiedInvestor":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_dataModification":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_push_queryPushStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxpService_adjustFunds":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_mainChangeObeyAllInOne":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_searchStkAcctBizInfoEx":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_unfreeze":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_historicaIncome":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_partnerInformation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_queryProductPurchase":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_getRapidRedeemBank":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_cams_getUserInfoById":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_ggt_submitSurveyAnswers":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_synCustPayAcctInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_placeReservedIPOsOrder":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_tsp_getUserInfoById":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_khpp_updateData":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_cashRapidRedeem":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_IDVerifyHessian":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_checkCashRapidRedeem":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_querySystemStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_searchStkAcctBizInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_getCustInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryShareProfit":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_uploadImage":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_addChannelSMS":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_fundCodeVerification":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_queryUserBasicInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_OpenAcc_checkChannelAuth":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_searchStkAcctBizInfoEx":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_queryTrdacct":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trdacct_findTracctByIdno":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_userOccuInfoMainten":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_fundAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_CancelIPOsTodayOrder":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_otc_cybSignResultCallBack":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_IdCardpromotionTract":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_verification":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_bankSecurityTransIn":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_getProtocolList":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_openQERNew":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_liftLossAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_aoi_querySpecialAgreement":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryDeliveryOrder":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_searchStkAcctBizInfoToEx":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_batch_runTbcTask":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryTrdacctByDates":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_queryAccounts":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kbss_getAccountByID":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_getAgreementInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_cts_zpqk":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_qtyFile":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_XjbAdd":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_queryCustAgreement":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_getAvailableNew":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_queryIPOChosenInfoNew":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_findTracctByIdno":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_app_search":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_trade_queryIPOChosenInfoNew":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_useInformation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kbss_synClientInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_accountCancellation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_queryExtAccByCustCode":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_savaQuestionnaire":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_antHangUp":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_operateStkAcctBizInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_getRetainShares":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_savaCustomer":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_aoi_queryHisRiskTest":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_findCust":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_checkSmsVerifyCode":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_cancelAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_appropriateSet":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_login":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryCustCommonInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_verify_verifyByChannel":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_getOpenaccInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_queryRiskInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_app_stocksearch":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_getEnumByType":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_queryRiskLevel":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_queryProductProportion":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryMatched":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_synCuacctInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_repurchaseOffer":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_submitOpenaccInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_pagedQueryMatched":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_searchYmtByCardNo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_IPO_queryIPOChosenInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_custCapitalInfoMainten":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_getCustAgmtStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_aoi_queryStockCodeAppro":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_canOpenQER":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_getAvailable":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_fundFile":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_ggt_getSurveyQuestions":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_savaRisk":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryNewShareAssignInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_queryKhppBatchInfoByUser":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_changeCashTreasureStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_midDataPersistence":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_openQualifiedInvestorRight":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_savaBank":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_getRishQuestions":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_signElectPromise":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryHisQuestions":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_imgReuslt":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_custRecordInfoMainten":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_dataCheck":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_setRetainShares":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_InformationInquiry":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_ggt_openGGT":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_queryAccountResult":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_readImg":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_accountActivation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_querySecuAcct":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_searchYmt":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_productPurchase":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_aoi_batchRiskSurvey":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_queryShares":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_beneficiaryInfoMainten":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"file_lfex_qtyFile":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryBeneficiaryInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_appropriateQuery":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_ymtCancellation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_getPledgeSharesList":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_uploadImg":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_savaCust":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_aoi_MessageRevealSN":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_listOfStkTrdAcct":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_signCashRapidRedeem":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_ocr_readImgText":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_securitiesAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_queryIPOsOrderInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_cams_listCuacct":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_modifyIPOsOrderInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_queryAppropriateSurveyRating":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_relationshipConfirmation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_getProtocolByID":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_preMainChangeObey":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_ymtApply":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_signElectContract":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_accountResult":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_getCustBaseInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_queryOrderInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_kcxp_queryCustCapitalInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_custInfoCheckOptn":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_custInfoManage":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_findProfession":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_delChannelSMS":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zhx_idCardAuthentication":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_securitiesAccountCreation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_updateCust":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_custBatchAnswer":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_getOcrUserInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_registAccountMaintain":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryIPOCalendar":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryShare":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_incidenceRelation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_savaCuacctPwd":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_aoi_queryRiskTest":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_queryAccountStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_signNewAgreement":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_resultQuery":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_lu_bindCode":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_queryCapital":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_searchStkAcctBizInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_cts_adjustFunds":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_estimateIncome":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_openDelistingStockTradeRight":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_updateQualifiedInvestor":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_querySecuInfo":{"comSign":"SBTPS-OPF-AIO-WEB-DMZPTR-AUTH-APP"},
"forward_sbtpsboa_queryIPOsSetExpDataInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_kcxp_queryControllerInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"file_lfex_fundFile":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_setCustAdequacyInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_queryUserBasicInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_cts_zpck":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_queryPersonalAsset":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_cybCanOpen":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kh_cybAddResultQuery":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_otc_riskDataUpload":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_xjbYieldRate":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryExtInstInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kbss_checkShareholderAccounts":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryQuotation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_bps_idNumberPromotion":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryCustRecordInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_controllerInfoMainten":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_verifyAntAccount":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryNewSharePayment":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_queryVideoVerify":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryFunds":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_findOpenAccountStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_queryUserBasicInfoExt":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_readImg":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_cancleOrder":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_custInfoCheckoptn":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_upp_privateStatusQuery":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_getUserInfoById":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_queryAccountStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_openacc_getRiskLevel":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_findRisk":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_placeReservedOrder":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_bps_operBoodsBizInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_sbtpsboa_IPOsOrderCancel":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_boa_queryIPOsOrderInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS","desensitizeKeyArray":["PWD","USER_PWD","pwd","AUTH_INFO","REQ_AUTH_INFO","REQ_EXT_ACC_PWD","EXT_ACC_PWD"]},
"forward_bps_signAgreement":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"file_lfex_preFundFile":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_batch_getTbcStatus":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_account_queryBjhgQualification":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_xjb_cashRedeem":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_banksecurityTransIn":{"comSign":"SBTPS-OPF-AIO-WEB-DMZPTR-AUTH-APP"},
"forward_zd_managementInformation":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_qer_getSupplyPledgeList":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_updateChannelSMS":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryUserSecuInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_banksecurityTransOut":{"comSign":"SBTPS-OPF-AIO-WEB-DMZPTR-AUTH-APP"},
"forward_common_searchStkAcctBizInfoEx":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_queryFundsFlow":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_tsp_login":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_soas_savaBatchMessage":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kcxp_queryUserByTel":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_merchandiseOrder":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_common_searchStkAcctBizInfo":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_kess_idVerify":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_push_cancelBind":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zhx_IdCardpromotion":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_trade_queryMaxShareQty":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"},
"forward_zd_searchStkAcctBizInfoToEx":{"comSign":"SBTPS-OPF-AIO-WEB-SF-AUTH-APP-ITS"}
}
Jenkins cmd指令 if %ZIP_NAME% == SBTPS-OPF-NGX-SF-NGINX (
cd openapi-nginx-sf-conf
xcopy "differ/fat/sf" "differ/fat" /y/s/e
xcopy "differ/uat/sf" "differ/uat" /y/s/e
xcopy "differ/prd/sf" "differ/prd" /y/s/e
zip -r SBTPS-OPF-NGX-SF-NGINX.zip common differ -x "differ/fat/dmz/*" -x "differ/fat/sf/*" -x "differ/uat/dmz/*" -x "differ/uat/sf/*" -x "differ/prd/dmz/*" -x "differ/prd/sf/*"
rd /s/q "differ/fat/servers"
rd /s/q "differ/uat/servers"
rd /s/q "differ/prd/servers"
cd differ/fat
del /q "nginx.conf"
cd ../../differ/uat
del /q "nginx.conf"
cd ../../differ/prd
del /q "nginx.conf"
)
if %ZIP_NAME% == SBTPS-OPF-NGX-DMZWEB-NGINX (
cd openapi-nginx-sf-conf
xcopy "differ/fat/dmz" "differ/fat" /y/s/e
xcopy "differ/uat/dmz" "differ/uat" /y/s/e
xcopy "differ/prd/dmz" "differ/prd" /y/s/e
zip -r SBTPS-OPF-NGX-DMZWEB-NGINX.zip common differ -x "differ/fat/dmz/*" -x "differ/fat/sf/*" -x "differ/uat/dmz/*" -x "differ/uat/sf/*" -x "differ/prd/dmz/*" -x "differ/prd/sf/*"
rd /s/q "differ/fat/servers"
rd /s/q "differ/uat/servers"
rd /s/q "differ/prd/servers"
cd differ/fat
del /q "nginx.conf"
cd ../../differ/uat
del /q "nginx.conf"
cd ../../differ/prd
del /q "nginx.conf"
)