mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-02 23:06:36 +08:00
feat(rate-limit): add default request rate limit configuration
- Support openresty_default_limit_req_per_ip in system_configs. - Add limit_req and limit_req_status 429 directive generation in openresty renderer. - Implement route-level limit_req_per_ip override and explicit disable. - Add frontend UI inputs and validation in rate limits tab config. - Update swagger API docs and changelog for v3.4.3-beta.3.
This commit is contained in:
@@ -531,6 +531,7 @@ func diffOpenRestyOptionDetails(left openRestyConfigSnapshot, right openRestyCon
|
||||
appendIfChanged("OpenRestyDefaultLimitConnPerServer", fmt.Sprintf("%d", left.DefaultLimitConnPerServer), fmt.Sprintf("%d", right.DefaultLimitConnPerServer))
|
||||
appendIfChanged("OpenRestyDefaultLimitConnPerIP", fmt.Sprintf("%d", left.DefaultLimitConnPerIP), fmt.Sprintf("%d", right.DefaultLimitConnPerIP))
|
||||
appendIfChanged("OpenRestyDefaultLimitRate", left.DefaultLimitRate, right.DefaultLimitRate)
|
||||
appendIfChanged("OpenRestyDefaultLimitReqPerIP", left.DefaultLimitReqPerIP, right.DefaultLimitReqPerIP)
|
||||
return changes
|
||||
}
|
||||
|
||||
@@ -582,5 +583,6 @@ func openRestyOptionKeys() []string {
|
||||
"OpenRestyDefaultLimitConnPerServer",
|
||||
"OpenRestyDefaultLimitConnPerIP",
|
||||
"OpenRestyDefaultLimitRate",
|
||||
"OpenRestyDefaultLimitReqPerIP",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ type snapshotRoute struct {
|
||||
LimitConnPerServer int `json:"limit_conn_per_server,omitempty"`
|
||||
LimitConnPerIP int `json:"limit_conn_per_ip,omitempty"`
|
||||
LimitRate string `json:"limit_rate,omitempty"`
|
||||
LimitReqPerIP string `json:"limit_req_per_ip,omitempty"`
|
||||
CacheEnabled bool `json:"cache_enabled"`
|
||||
CachePolicy string `json:"cache_policy,omitempty"`
|
||||
CacheRules []string `json:"cache_rules,omitempty"`
|
||||
@@ -138,6 +139,7 @@ type openRestyConfigSnapshot struct {
|
||||
DefaultLimitConnPerServer int `json:"default_limit_conn_per_server,omitempty"`
|
||||
DefaultLimitConnPerIP int `json:"default_limit_conn_per_ip,omitempty"`
|
||||
DefaultLimitRate string `json:"default_limit_rate,omitempty"`
|
||||
DefaultLimitReqPerIP string `json:"default_limit_req_per_ip,omitempty"`
|
||||
}
|
||||
|
||||
type snapshotDocument struct {
|
||||
@@ -285,6 +287,7 @@ func buildSnapshotRoutes(ctx context.Context, routes []*model.ProxyRoute) ([]sna
|
||||
LimitConnPerServer: route.LimitConnPerServer,
|
||||
LimitConnPerIP: route.LimitConnPerIP,
|
||||
LimitRate: route.LimitRate,
|
||||
LimitReqPerIP: route.LimitReqPerIP,
|
||||
CacheEnabled: route.CacheEnabled,
|
||||
CachePolicy: route.CachePolicy,
|
||||
CacheRules: cacheRules,
|
||||
@@ -548,10 +551,14 @@ func buildOpenRestyConfigSnapshot(ctx context.Context) openRestyConfigSnapshot {
|
||||
DefaultLimitConnPerServer: getNonNegIntConfig(model.ConfigKeyOpenRestyDefaultLimitConnPerServer, 0),
|
||||
DefaultLimitConnPerIP: getNonNegIntConfig(model.ConfigKeyOpenRestyDefaultLimitConnPerIP, 0),
|
||||
DefaultLimitRate: strings.ToLower(strings.TrimSpace(getStringConfig(model.ConfigKeyOpenRestyDefaultLimitRate, ""))),
|
||||
DefaultLimitReqPerIP: strings.ToLower(strings.TrimSpace(getStringConfig(model.ConfigKeyOpenRestyDefaultLimitReqPerIP, ""))),
|
||||
}
|
||||
if snapshot.DefaultLimitRate == "0" {
|
||||
snapshot.DefaultLimitRate = ""
|
||||
}
|
||||
if snapshot.DefaultLimitReqPerIP == "0" {
|
||||
snapshot.DefaultLimitReqPerIP = ""
|
||||
}
|
||||
snapshot.CachePath = normalizeProxyCachePathForSnapshot(snapshot.CacheEnabled, snapshot.CachePath)
|
||||
return snapshot
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ var openRestyOptionValidators = map[string]func(key, value string) error{
|
||||
model.ConfigKeyOpenRestyDefaultLimitConnPerServer: validateNonNegativeIntegerOption,
|
||||
model.ConfigKeyOpenRestyDefaultLimitConnPerIP: validateNonNegativeIntegerOption,
|
||||
model.ConfigKeyOpenRestyDefaultLimitRate: validateOpenRestyDefaultLimitRate,
|
||||
model.ConfigKeyOpenRestyDefaultLimitReqPerIP: validateOpenRestyDefaultLimitReqPerIP,
|
||||
}
|
||||
|
||||
var openRestyDefaultLimitRatePattern = regexp.MustCompile(`^\d+[kKmM]?$`)
|
||||
@@ -194,3 +195,15 @@ func validateOpenRestyDefaultLimitRate(key, trimmed string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var openRestyDefaultLimitReqPerIPPattern = regexp.MustCompile(`^\d+r/[sm]$`)
|
||||
|
||||
func validateOpenRestyDefaultLimitReqPerIP(key, trimmed string) error {
|
||||
if trimmed == "" || trimmed == "0" {
|
||||
return nil
|
||||
}
|
||||
if !openRestyDefaultLimitReqPerIPPattern.MatchString(strings.ToLower(trimmed)) {
|
||||
return fmt.Errorf("%s 格式不合法,请输入类似 10r/s、100r/m,或留空关闭", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func populateProxyRouteFields(
|
||||
upstreams []string,
|
||||
originHost, cachePolicy string,
|
||||
limitConnPerServer, limitConnPerIP int,
|
||||
limitRate, upstreamType string,
|
||||
limitRate, limitReqPerIP, upstreamType string,
|
||||
) {
|
||||
route.SiteName = siteName
|
||||
route.OriginID = originID
|
||||
@@ -103,6 +103,7 @@ func populateProxyRouteFields(
|
||||
route.LimitConnPerServer = limitConnPerServer
|
||||
route.LimitConnPerIP = limitConnPerIP
|
||||
route.LimitRate = limitRate
|
||||
route.LimitReqPerIP = limitReqPerIP
|
||||
route.CacheEnabled = input.CacheEnabled
|
||||
route.CachePolicy = normalizeCachePolicy(input.CacheEnabled, cachePolicy)
|
||||
route.CacheRules = jsonFields.cacheRulesJSON
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
var proxyHeaderKeyPattern = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
|
||||
var proxyRouteLimitRatePattern = regexp.MustCompile(`^\d+[kKmM]?$`)
|
||||
var proxyRouteLimitReqPattern = regexp.MustCompile(`^\d+r/[sm]$`)
|
||||
|
||||
const (
|
||||
proxyRouteCachePolicyStatic = "static"
|
||||
@@ -349,6 +350,20 @@ func normalizeProxyRouteLimitRate(raw string) (string, error) {
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
func normalizeProxyRouteLimitReqPerIP(raw string) (string, error) {
|
||||
normalized := strings.ToLower(strings.TrimSpace(raw))
|
||||
if normalized == "" || normalized == "0" {
|
||||
return "", nil
|
||||
}
|
||||
if normalized == "-1" {
|
||||
return "-1", nil
|
||||
}
|
||||
if !proxyRouteLimitReqPattern.MatchString(normalized) {
|
||||
return "", errors.New("请求频率格式不合法,请使用类似 10r/s、100r/m,或 -1 禁用")
|
||||
}
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
func hasStructuredOriginInput(input Input) bool {
|
||||
return (input.OriginID != nil && *input.OriginID != 0) ||
|
||||
strings.TrimSpace(input.OriginScheme) != "" ||
|
||||
|
||||
@@ -40,6 +40,7 @@ type Input struct {
|
||||
LimitConnPerServer int `json:"limit_conn_per_server"`
|
||||
LimitConnPerIP int `json:"limit_conn_per_ip"`
|
||||
LimitRate string `json:"limit_rate"`
|
||||
LimitReqPerIP string `json:"limit_req_per_ip"`
|
||||
CacheEnabled bool `json:"cache_enabled"`
|
||||
CachePolicy string `json:"cache_policy"`
|
||||
CacheRules []string `json:"cache_rules"`
|
||||
@@ -72,6 +73,7 @@ type View struct {
|
||||
LimitConnPerServer int `json:"limit_conn_per_server"`
|
||||
LimitConnPerIP int `json:"limit_conn_per_ip"`
|
||||
LimitRate string `json:"limit_rate"`
|
||||
LimitReqPerIP string `json:"limit_req_per_ip"`
|
||||
CacheEnabled bool `json:"cache_enabled"`
|
||||
CachePolicy string `json:"cache_policy"`
|
||||
CacheRules string `json:"cache_rules"`
|
||||
@@ -267,6 +269,10 @@ func buildProxyRoute(ctx context.Context, route *model.ProxyRoute, input Input)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
limitReqPerIP, err := normalizeProxyRouteLimitReqPerIP(input.LimitReqPerIP)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := validateProxyRouteZoneDomainCertificates(ctx, domains, input.EnableHTTPS); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -307,6 +313,7 @@ func buildProxyRoute(ctx context.Context, route *model.ProxyRoute, input Input)
|
||||
limitConnPerServer,
|
||||
limitConnPerIP,
|
||||
limitRate,
|
||||
limitReqPerIP,
|
||||
upstreamType,
|
||||
)
|
||||
if err := applyProxyRouteUpstreamType(ctx, route, upstreamType, input); err != nil {
|
||||
@@ -369,6 +376,7 @@ func buildProxyRouteView(ctx context.Context, route *model.ProxyRoute) (*View, e
|
||||
LimitConnPerServer: route.LimitConnPerServer,
|
||||
LimitConnPerIP: route.LimitConnPerIP,
|
||||
LimitRate: route.LimitRate,
|
||||
LimitReqPerIP: route.LimitReqPerIP,
|
||||
CacheEnabled: route.CacheEnabled,
|
||||
CachePolicy: displayCachePolicy(route.CacheEnabled, route.CachePolicy),
|
||||
CacheRules: route.CacheRules,
|
||||
|
||||
Reference in New Issue
Block a user