From df71a4d07a5da12e13a21405550f99a51f257181 Mon Sep 17 00:00:00 2001 From: sunface Date: Wed, 5 Sep 2018 14:19:54 +0800 Subject: [PATCH] resolved #8 --- api/api_server.go | 3 +++ api/load_data.go | 4 ++-- api/manage/api.go | 44 ++++++++++++++++++++++++++------------------ api/manage/ecode.go | 15 +++++++++------ api/router.go | 15 ++++++++++++--- api/sql_data/juz.sql | 16 ++++++++++------ misc/const.go | 3 +++ misc/data.go | 10 ++++++---- 8 files changed, 71 insertions(+), 39 deletions(-) diff --git a/api/api_server.go b/api/api_server.go index 20ce1270..c2cfe8c9 100644 --- a/api/api_server.go +++ b/api/api_server.go @@ -27,6 +27,9 @@ type ApiServer struct { func (p *ApiServer) Start() { g.Info("start tfe..") + // 获取所有内部服务节点信息 + g.ETCD.QueryAll(misc.Conf.Etcd.Addrs) + // 初始化mysql连接 misc.InitMysql() diff --git a/api/load_data.go b/api/load_data.go index 1db3cecf..059a2016 100644 --- a/api/load_data.go +++ b/api/load_data.go @@ -20,8 +20,8 @@ func (p *ApiServer) loadData() { now := time.Now() date := talent.Time2StringSecond(time.Now()) version := talent.Time2Version(now) - g.DB.Exec(fmt.Sprintf("insert into api_release (service,api_id,description,mock_data,route_type,route_addr,app,create_date) values('admin','admin.test.get.v1','','',1,'http://httpbin.org/get','admin','%s')", date)) - g.DB.Exec(fmt.Sprintf("insert into api_define (service,api_id,description,mock_data,route_type,route_addr,revise_version,release_version,app,create_date) values('admin','admin.test.get.v1','','',1,'http://httpbin.org/get','%s','%s','admin','%s')", version, version, date)) + g.DB.Exec(fmt.Sprintf("insert into api_release (service,api_id,description,mock_data,route_type,backend_addr,app,create_date) values('admin','admin.test.get.v1','','',1,'http://httpbin.org/get','admin','%s')", date)) + g.DB.Exec(fmt.Sprintf("insert into api_define (service,api_id,description,mock_data,route_type,backend_addr,revise_version,release_version,app,create_date) values('admin','admin.test.get.v1','','',1,'http://httpbin.org/get','%s','%s','admin','%s')", version, version, date)) lastLoadTime = time.Now() // 加载所有数据 diff --git a/api/manage/api.go b/api/manage/api.go index 0b45f63d..8fd853ca 100644 --- a/api/manage/api.go +++ b/api/manage/api.go @@ -144,9 +144,9 @@ func (m *Manage) DefineAPI(c echo.Context) error { pr := g.B64.EncodeToString(talent.String2Bytes(*api.ParamTable)) if action == "create" { - query := fmt.Sprintf(`insert into api_define (api_id,path_type,service,description,route_type,route_addr,route_proto,bw_strategy,retry_strategy,traffic_strategy,mock_data,traffic_on,traffic_api,traffic_ratio,traffic_ips,verify_on,param_rules,cached_time,revise_version,create_date,app) - values ('%s','%d','%s','%s','%d','%s','%d','%d','%d','%d','%s','%d','%s','%d','%s','%d','%s','%d','%s', '%s','%s')`, - api.APIID, api.PathType, api.Service, *api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, api.BwStrategy, api.RetryStrategy, api.TrafficStrategy, *api.MockData, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, pr, api.CachedTime, talent.Time2Version(now), date, api.App) + query := fmt.Sprintf(`insert into api_define (api_id,path_type,service,description,route_type,backend_addr,backend_type,bw_strategy,retry_strategy,traffic_strategy,mock_data,traffic_on,traffic_api,traffic_ratio,traffic_ips,verify_on,param_rules,cached_time,revise_version,create_date,app,addr_type,backend_uri) + values ('%s','%d','%s','%s','%d','%s','%d','%d','%d','%d','%s','%d','%s','%d','%s','%d','%s','%d','%s', '%s','%s','%d','%s')`, + api.APIID, api.PathType, api.Service, *api.Desc, api.RouteType, api.BackendAddr, api.BackendType, api.BwStrategy, api.RetryStrategy, api.TrafficStrategy, *api.MockData, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, pr, api.CachedTime, talent.Time2Version(now), date, api.App, api.AddrType, api.BackendURI) _, err := g.DB.Exec(query) if err != nil { if strings.Contains(err.Error(), g.DUP_KEY_ERR) { @@ -165,8 +165,8 @@ func (m *Manage) DefineAPI(c echo.Context) error { } // 初始化api发布表,并设置为未发布状态 // 这里把不能再修改的值进行初始化 - query = fmt.Sprintf(`insert into api_release (api_id,path_type,service,route_addr,status,create_date) values ('%s','%d','%s','%s','%d','%s')`, - api.APIID, api.PathType, api.Service, api.RouteAddr, misc.API_OFFLINE, date) + query = fmt.Sprintf(`insert into api_release (api_id,path_type,service,backend_addr,status,create_date) values ('%s','%d','%s','%s','%d','%s')`, + api.APIID, api.PathType, api.Service, api.BackendAddr, misc.API_OFFLINE, date) _, err = g.DB.Exec(query) if err != nil { g.Info("access database error", zap.Error(err), zap.String("query", query)) @@ -178,8 +178,8 @@ func (m *Manage) DefineAPI(c echo.Context) error { } audit.Log(c.FormValue("username"), api.Service, audit.TypeApi, api.APIID, audit.OpCreate, c.FormValue("api"), "") } else { - query := fmt.Sprintf("update api_define set description='%s',route_type='%d',route_addr='%s',route_proto='%d',bw_strategy='%d',retry_strategy='%d',traffic_strategy='%d',mock_data='%s',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s',cached_time='%d',app='%s' where api_id='%s'", - *api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, api.BwStrategy, api.RetryStrategy, api.TrafficStrategy, *api.MockData, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, pr, api.CachedTime, api.App, api.APIID) + query := fmt.Sprintf("update api_define set description='%s',route_type='%d',backend_addr='%s',backend_type='%d',bw_strategy='%d',retry_strategy='%d',traffic_strategy='%d',mock_data='%s',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s',cached_time='%d',app='%s',addr_type='%d',backend_uri='%s' where api_id='%s'", + *api.Desc, api.RouteType, api.BackendAddr, api.BackendType, api.BwStrategy, api.RetryStrategy, api.TrafficStrategy, *api.MockData, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, pr, api.CachedTime, api.App, api.AddrType, api.BackendURI, api.APIID) res, err := g.DB.Exec(query) if err != nil { g.Info("access database error", zap.Error(err), zap.String("query", query)) @@ -374,18 +374,26 @@ func (m *Manage) parseAPI(c echo.Context) (*misc.API, int, string) { return nil, ApiWithServiceSuffixC, ApiWithServiceSuffixE } - if api.RouteAddr == "" || strings.TrimSpace(api.RouteAddr) == "http://" || strings.TrimSpace(api.RouteAddr) == "https://" { - return nil, RouteAddrEmptyC, RouteAddrEmptyE + if api.BackendAddr == "" { + return nil, BackendAddrEmptyC, BackendAddrEmptyE } - if api.RouteAddr != "" { - if !strings.HasPrefix(api.RouteAddr, "http") { - return nil, RouteAddrWithHTTPPrefixC, RouteAddrWithHTTPPrefixE + if api.AddrType == misc.ADDR_URL { + if strings.TrimSpace(api.BackendAddr) == "http://" || strings.TrimSpace(api.BackendAddr) == "https://" { + return nil, BackendAddrEmptyC, BackendAddrEmptyE + } + + if !strings.HasPrefix(api.BackendAddr, "http") { + return nil, BackendAddrWithHTTPPrefixC, BackendAddrWithHTTPPrefixE + } + } else { + if !talent.OnlyAlphaNumAndUri(api.BackendURI) { + return nil, UriAlphaNumAndUriC, UriAlphaNumAndUriE } } - if (api.RouteProto != 1) && (api.RouteProto != 2) { - return nil, RouteProtoInvalidC, RouteProtoInvalidE + if (api.BackendType != 1) && (api.BackendType != 2) { + return nil, BackendTypeInvalidC, BackendTypeInvalidE } if api.TrafficAPI != "" { @@ -449,8 +457,8 @@ func (m *Manage) APIRelease(c echo.Context) error { } // 更新release - query = fmt.Sprintf("update api_release set description='%s',route_type='%d',route_addr='%s',route_proto='%d',mock_data='%s',retry_strategy='%d',bw_strategy='%d',traffic_strategy='%d',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s', cached_time='%d',status='%d',app='%s' where api_id='%s'", - *api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, *api.MockData, api.RetryStrategy, api.BwStrategy, api.TrafficStrategy, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, *api.ParamTable, api.CachedTime, misc.API_RELEASED, api.App, api.APIID) + query = fmt.Sprintf("update api_release set description='%s',route_type='%d',backend_addr='%s',backend_type='%d',mock_data='%s',retry_strategy='%d',bw_strategy='%d',traffic_strategy='%d',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s', cached_time='%d',status='%d',app='%s',addr_type='%d',backend_uri='%s' where api_id='%s'", + *api.Desc, api.RouteType, api.BackendAddr, api.BackendType, *api.MockData, api.RetryStrategy, api.BwStrategy, api.TrafficStrategy, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, *api.ParamTable, api.CachedTime, misc.API_RELEASED, api.App, api.AddrType, api.BackendURI, api.APIID) _, err = g.DB.Exec(query) if err != nil { @@ -794,8 +802,8 @@ func (m *Manage) APIBatchRelease(c echo.Context) error { } // 更新release - query = fmt.Sprintf("update api_release set description='%s',route_type='%d',route_addr='%s',route_proto='%d',mock_data='%s',retry_strategy='%d',bw_strategy='%d',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s', cached_time='%d',status='%d',app='%s' where api_id='%s'", - *api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, *api.MockData, api.RetryStrategy, api.BwStrategy, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, *api.ParamTable, api.CachedTime, misc.API_RELEASED, api.App, api.APIID) + query = fmt.Sprintf("update api_release set description='%s',route_type='%d',backend_addr='%s',backend_type='%d',mock_data='%s',retry_strategy='%d',bw_strategy='%d',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s', cached_time='%d',status='%d',app='%s',addr_type='%d',backend_uri='%s' where api_id='%s'", + *api.Desc, api.RouteType, api.BackendAddr, api.BackendType, *api.MockData, api.RetryStrategy, api.BwStrategy, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, *api.ParamTable, api.CachedTime, misc.API_RELEASED, api.App, api.AddrType, api.BackendURI, api.APIID) _, err = g.DB.Exec(query) if err != nil { diff --git a/api/manage/ecode.go b/api/manage/ecode.go index 82c64bd7..fdf37cd4 100644 --- a/api/manage/ecode.go +++ b/api/manage/ecode.go @@ -21,14 +21,14 @@ const ( ApiOnlyAlphaNumAndDotC = 10006 ApiOnlyAlphaNumAndDotE = "API name can only be consisted of alphabet and numberic" - RouteAddrWithHTTPPrefixC = 10007 - RouteAddrWithHTTPPrefixE = "Backend url must prefix with http:// or https://" + BackendAddrWithHTTPPrefixC = 10007 + BackendAddrWithHTTPPrefixE = "Backend url must prefix with http:// or https://" - RouteAddrEmptyC = 10008 - RouteAddrEmptyE = "Backend url cant be empty" + BackendAddrEmptyC = 10008 + BackendAddrEmptyE = "Backend url cant be empty" - RouteProtoInvalidC = 10009 - RouteProtoInvalidE = "Backend type invalid" + BackendTypeInvalidC = 10009 + BackendTypeInvalidE = "Backend type invalid" ReqTimeoutInvalidC = 10010 ReqTimeoutInvalidE = "Timeout must be in (0,60]" @@ -65,4 +65,7 @@ const ( StrategyNameExistE = "Strategy name already exist" StrategyNameExistc = 1061 + + UriAlphaNumAndUriC = 10062 + UriAlphaNumAndUriE = "uri can only be consisted of alphabet,numberic and /" ) diff --git a/api/router.go b/api/router.go index 82321845..40bb135a 100644 --- a/api/router.go +++ b/api/router.go @@ -92,7 +92,7 @@ func (router *router) route(c echo.Context) error { func (rt *router) redirect(c echo.Context, r *req.Request) error { // 组装参数 - url := r.Api.RouteAddr + "?" + c.QueryString() + url := r.Api.BackendAddr + "?" + c.QueryString() return c.Redirect(http.StatusMovedPermanently, url) } @@ -118,7 +118,17 @@ func (rt *router) sync(r *req.Request) (int, []byte, error) { // 写入客户端真实ip req.Header.Set("X-Forwarded-For", r.ClientIP) - url := r.Api.RouteAddr + var url string + // 获取url + if r.Api.AddrType == misc.ADDR_URL { // direct url + url = r.Api.BackendAddr + } else { // get url from etcd + s := g.GetServer(r.Api.BackendAddr) + if s == nil { + return http.StatusServiceUnavailable, nil, errors.New("no target server available") + } + url = "http://" + s.IP + r.Api.BackendURI + } switch r.Method { case "GET": // 拼接url @@ -126,7 +136,6 @@ func (rt *router) sync(r *req.Request) (int, []byte, error) { default: args.WriteTo(req.BodyWriter()) } - req.SetRequestURI(url) // 超时重试 diff --git a/api/sql_data/juz.sql b/api/sql_data/juz.sql index 49f871fb..a06244ba 100644 --- a/api/sql_data/juz.sql +++ b/api/sql_data/juz.sql @@ -8,9 +8,11 @@ CREATE TABLE IF NOT EXISTS `api_release` ( `service` varchar(255) NOT NULL COMMENT 'service名', `description` text COMMENT '介绍', - `route_type` int(11) NOT NULL DEFAULT '1' COMMENT '代理类型', - `route_addr` varchar(255) NOT NULL COMMENT '后段服务地址', - `route_proto` int(11) DEFAULT '1' COMMENT '后端服务协议', + `route_type` int(11) NOT NULL DEFAULT '1' COMMENT '代理类型,1: direct 2: redirect', + `addr_type` int(11) DEFAULT '1' COMMENT '后端地址类型,1:直接寻址 2: ETCD服务发现', + `backend_addr` varchar(255) NOT NULL COMMENT '后段服务地址', + `backend_uri` varchar(255) DEFAUlT '' COMMENT '后端服务URI路径', + `backend_type` int(11) DEFAULT '1' COMMENT '后端服务协议,1: HTTP(S) 2: Mock', `mock_data` text COMMENT 'mock类型接口,返回定义的mock数据', `retry_strategy` int(11) DEFAULT '0' COMMENT '重试策略ID', @@ -46,9 +48,11 @@ CREATE TABLE IF NOT EXISTS `api_define` ( `service` varchar(255) NOT NULL COMMENT 'service名', `description` text COMMENT '介绍', - `route_type` int(11) NOT NULL DEFAULT '1' COMMENT '代理类型', - `route_addr` varchar(255) NOT NULL COMMENT '后段服务地址', - `route_proto` int(11) DEFAULT '1' COMMENT '后端服务协议', + `route_type` int(11) NOT NULL DEFAULT '1' COMMENT '代理类型,1: direct 2: redirect', + `addr_type` int(11) DEFAULT '1' COMMENT '后端地址类型,1:直接寻址 2: ETCD服务发现', + `backend_addr` varchar(255) NOT NULL COMMENT '后段服务地址', + `backend_uri` varchar(255) DEFAUlT '' COMMENT '后端服务URI路径', + `backend_type` int(11) DEFAULT '1' COMMENT '后端服务协议,1: HTTP(S) 2: Mock', `mock_data` text COMMENT 'mock类型接口,返回定义的mock数据', `retry_strategy` int(11) DEFAULT '0' COMMENT '重试策略ID', diff --git a/misc/const.go b/misc/const.go index a31b4b91..27a18274 100644 --- a/misc/const.go +++ b/misc/const.go @@ -50,6 +50,9 @@ const ( STRATEGY_ON = 1 STRATEGY_OFF = 0 + + ADDR_URL = 1 + ADDR_ETCD = 2 ) // redis后缀 diff --git a/misc/data.go b/misc/data.go index 108481ce..99837c6f 100644 --- a/misc/data.go +++ b/misc/data.go @@ -18,10 +18,12 @@ type API struct { PathType int `db:"path_type" json:"path_type"` Desc *string `db:"description" json:"desc"` - RouteType int `db:"route_type" json:"route_type"` - RouteAddr string `db:"route_addr" json:"route_addr"` - RouteProto int `db:"route_proto" json:"route_proto"` - MockData *string `db:"mock_data" json:"mock_data"` + RouteType int `db:"route_type" json:"route_type"` + AddrType int `db:"addr_type" json:"addr_type"` + BackendAddr string `db:"backend_addr" json:"backend_addr"` + BackendURI string `db:"backend_uri" json:"backend_uri"` + BackendType int `db:"backend_type" json:"backend_type"` + MockData *string `db:"mock_data" json:"mock_data"` // 通用策略 RetryStrategy int `db:"retry_strategy" json:"retry_strategy"`