Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
14d2290b
authored
Jan 21, 2026
by
Calcium-Ion
Committed by
GitHub
Jan 21, 2026
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2663 from seefs001/feature/retry-status-code
feat: customizable automatic retry status codes
parents
817006d8
9a7fa9d1
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
204 additions
and
71 deletions
+204
-71
controller/option.go
+9
-0
controller/relay.go
+6
-21
model/option.go
+3
-0
setting/operation_setting/status_code_ranges.go
+50
-13
setting/operation_setting/status_code_ranges_test.go
+27
-0
web/src/components/settings/HttpStatusCodeRulesInput.jsx
+71
-0
web/src/components/settings/OperationSetting.jsx
+1
-0
web/src/i18n/locales/en.json
+2
-0
web/src/i18n/locales/zh.json
+2
-0
web/src/pages/Setting/Operation/SettingsMonitoring.jsx
+33
-37
No files found.
controller/option.go
View file @
14d2290b
...
@@ -187,6 +187,15 @@ func UpdateOption(c *gin.Context) {
...
@@ -187,6 +187,15 @@ func UpdateOption(c *gin.Context) {
})
})
return
return
}
}
case
"AutomaticRetryStatusCodes"
:
_
,
err
=
operation_setting
.
ParseHTTPStatusCodeRanges
(
option
.
Value
.
(
string
))
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
err
.
Error
(),
})
return
}
case
"console_setting.api_info"
:
case
"console_setting.api_info"
:
err
=
console_setting
.
ValidateConsoleSettings
(
option
.
Value
.
(
string
),
"ApiInfo"
)
err
=
console_setting
.
ValidateConsoleSettings
(
option
.
Value
.
(
string
),
"ApiInfo"
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
controller/relay.go
View file @
14d2290b
...
@@ -21,6 +21,7 @@ import (
...
@@ -21,6 +21,7 @@ import (
"github.com/QuantumNous/new-api/relay/helper"
"github.com/QuantumNous/new-api/relay/helper"
"github.com/QuantumNous/new-api/service"
"github.com/QuantumNous/new-api/service"
"github.com/QuantumNous/new-api/setting"
"github.com/QuantumNous/new-api/setting"
"github.com/QuantumNous/new-api/setting/operation_setting"
"github.com/QuantumNous/new-api/types"
"github.com/QuantumNous/new-api/types"
"github.com/bytedance/gopkg/util/gopool"
"github.com/bytedance/gopkg/util/gopool"
...
@@ -316,30 +317,14 @@ func shouldRetry(c *gin.Context, openaiErr *types.NewAPIError, retryTimes int) b
...
@@ -316,30 +317,14 @@ func shouldRetry(c *gin.Context, openaiErr *types.NewAPIError, retryTimes int) b
if
_
,
ok
:=
c
.
Get
(
"specific_channel_id"
);
ok
{
if
_
,
ok
:=
c
.
Get
(
"specific_channel_id"
);
ok
{
return
false
return
false
}
}
if
openaiErr
.
StatusCode
==
http
.
StatusTooManyRequests
{
code
:=
openaiErr
.
StatusCode
return
true
if
code
>=
200
&&
code
<
300
{
}
if
openaiErr
.
StatusCode
==
307
{
return
true
}
if
openaiErr
.
StatusCode
/
100
==
5
{
// 超时不重试
if
openaiErr
.
StatusCode
==
504
||
openaiErr
.
StatusCode
==
524
{
return
false
}
return
true
}
if
openaiErr
.
StatusCode
==
http
.
StatusBadRequest
{
return
false
}
if
openaiErr
.
StatusCode
==
408
{
// azure处理超时不重试
return
false
return
false
}
}
if
openaiErr
.
StatusCode
/
100
==
2
{
if
code
<
100
||
code
>
599
{
return
fals
e
return
tru
e
}
}
return
true
return
operation_setting
.
ShouldRetryByStatusCode
(
code
)
}
}
func
processChannelError
(
c
*
gin
.
Context
,
channelError
types
.
ChannelError
,
err
*
types
.
NewAPIError
)
{
func
processChannelError
(
c
*
gin
.
Context
,
channelError
types
.
ChannelError
,
err
*
types
.
NewAPIError
)
{
...
...
model/option.go
View file @
14d2290b
...
@@ -144,6 +144,7 @@ func InitOptionMap() {
...
@@ -144,6 +144,7 @@ func InitOptionMap() {
common
.
OptionMap
[
"StreamCacheQueueLength"
]
=
strconv
.
Itoa
(
setting
.
StreamCacheQueueLength
)
common
.
OptionMap
[
"StreamCacheQueueLength"
]
=
strconv
.
Itoa
(
setting
.
StreamCacheQueueLength
)
common
.
OptionMap
[
"AutomaticDisableKeywords"
]
=
operation_setting
.
AutomaticDisableKeywordsToString
()
common
.
OptionMap
[
"AutomaticDisableKeywords"
]
=
operation_setting
.
AutomaticDisableKeywordsToString
()
common
.
OptionMap
[
"AutomaticDisableStatusCodes"
]
=
operation_setting
.
AutomaticDisableStatusCodesToString
()
common
.
OptionMap
[
"AutomaticDisableStatusCodes"
]
=
operation_setting
.
AutomaticDisableStatusCodesToString
()
common
.
OptionMap
[
"AutomaticRetryStatusCodes"
]
=
operation_setting
.
AutomaticRetryStatusCodesToString
()
common
.
OptionMap
[
"ExposeRatioEnabled"
]
=
strconv
.
FormatBool
(
ratio_setting
.
IsExposeRatioEnabled
())
common
.
OptionMap
[
"ExposeRatioEnabled"
]
=
strconv
.
FormatBool
(
ratio_setting
.
IsExposeRatioEnabled
())
// 自动添加所有注册的模型配置
// 自动添加所有注册的模型配置
...
@@ -447,6 +448,8 @@ func updateOptionMap(key string, value string) (err error) {
...
@@ -447,6 +448,8 @@ func updateOptionMap(key string, value string) (err error) {
operation_setting
.
AutomaticDisableKeywordsFromString
(
value
)
operation_setting
.
AutomaticDisableKeywordsFromString
(
value
)
case
"AutomaticDisableStatusCodes"
:
case
"AutomaticDisableStatusCodes"
:
err
=
operation_setting
.
AutomaticDisableStatusCodesFromString
(
value
)
err
=
operation_setting
.
AutomaticDisableStatusCodesFromString
(
value
)
case
"AutomaticRetryStatusCodes"
:
err
=
operation_setting
.
AutomaticRetryStatusCodesFromString
(
value
)
case
"StreamCacheQueueLength"
:
case
"StreamCacheQueueLength"
:
setting
.
StreamCacheQueueLength
,
_
=
strconv
.
Atoi
(
value
)
setting
.
StreamCacheQueueLength
,
_
=
strconv
.
Atoi
(
value
)
case
"PayMethods"
:
case
"PayMethods"
:
...
...
setting/operation_setting/status_code_ranges.go
View file @
14d2290b
...
@@ -14,19 +14,20 @@ type StatusCodeRange struct {
...
@@ -14,19 +14,20 @@ type StatusCodeRange struct {
var
AutomaticDisableStatusCodeRanges
=
[]
StatusCodeRange
{{
Start
:
401
,
End
:
401
}}
var
AutomaticDisableStatusCodeRanges
=
[]
StatusCodeRange
{{
Start
:
401
,
End
:
401
}}
// Default behavior matches legacy hardcoded retry rules in controller/relay.go shouldRetry:
// retry for 1xx, 3xx, 4xx(except 400/408), 5xx(except 504/524), and no retry for 2xx.
var
AutomaticRetryStatusCodeRanges
=
[]
StatusCodeRange
{
{
Start
:
100
,
End
:
199
},
{
Start
:
300
,
End
:
399
},
{
Start
:
401
,
End
:
407
},
{
Start
:
409
,
End
:
499
},
{
Start
:
500
,
End
:
503
},
{
Start
:
505
,
End
:
523
},
{
Start
:
525
,
End
:
599
},
}
func
AutomaticDisableStatusCodesToString
()
string
{
func
AutomaticDisableStatusCodesToString
()
string
{
if
len
(
AutomaticDisableStatusCodeRanges
)
==
0
{
return
statusCodeRangesToString
(
AutomaticDisableStatusCodeRanges
)
return
""
}
parts
:=
make
([]
string
,
0
,
len
(
AutomaticDisableStatusCodeRanges
))
for
_
,
r
:=
range
AutomaticDisableStatusCodeRanges
{
if
r
.
Start
==
r
.
End
{
parts
=
append
(
parts
,
strconv
.
Itoa
(
r
.
Start
))
continue
}
parts
=
append
(
parts
,
fmt
.
Sprintf
(
"%d-%d"
,
r
.
Start
,
r
.
End
))
}
return
strings
.
Join
(
parts
,
","
)
}
}
func
AutomaticDisableStatusCodesFromString
(
s
string
)
error
{
func
AutomaticDisableStatusCodesFromString
(
s
string
)
error
{
...
@@ -39,10 +40,46 @@ func AutomaticDisableStatusCodesFromString(s string) error {
...
@@ -39,10 +40,46 @@ func AutomaticDisableStatusCodesFromString(s string) error {
}
}
func
ShouldDisableByStatusCode
(
code
int
)
bool
{
func
ShouldDisableByStatusCode
(
code
int
)
bool
{
return
shouldMatchStatusCodeRanges
(
AutomaticDisableStatusCodeRanges
,
code
)
}
func
AutomaticRetryStatusCodesToString
()
string
{
return
statusCodeRangesToString
(
AutomaticRetryStatusCodeRanges
)
}
func
AutomaticRetryStatusCodesFromString
(
s
string
)
error
{
ranges
,
err
:=
ParseHTTPStatusCodeRanges
(
s
)
if
err
!=
nil
{
return
err
}
AutomaticRetryStatusCodeRanges
=
ranges
return
nil
}
func
ShouldRetryByStatusCode
(
code
int
)
bool
{
return
shouldMatchStatusCodeRanges
(
AutomaticRetryStatusCodeRanges
,
code
)
}
func
statusCodeRangesToString
(
ranges
[]
StatusCodeRange
)
string
{
if
len
(
ranges
)
==
0
{
return
""
}
parts
:=
make
([]
string
,
0
,
len
(
ranges
))
for
_
,
r
:=
range
ranges
{
if
r
.
Start
==
r
.
End
{
parts
=
append
(
parts
,
strconv
.
Itoa
(
r
.
Start
))
continue
}
parts
=
append
(
parts
,
fmt
.
Sprintf
(
"%d-%d"
,
r
.
Start
,
r
.
End
))
}
return
strings
.
Join
(
parts
,
","
)
}
func
shouldMatchStatusCodeRanges
(
ranges
[]
StatusCodeRange
,
code
int
)
bool
{
if
code
<
100
||
code
>
599
{
if
code
<
100
||
code
>
599
{
return
false
return
false
}
}
for
_
,
r
:=
range
AutomaticDisableStatusCodeR
anges
{
for
_
,
r
:=
range
r
anges
{
if
code
<
r
.
Start
{
if
code
<
r
.
Start
{
return
false
return
false
}
}
...
...
setting/operation_setting/status_code_ranges_test.go
View file @
14d2290b
...
@@ -50,3 +50,30 @@ func TestShouldDisableByStatusCode(t *testing.T) {
...
@@ -50,3 +50,30 @@ func TestShouldDisableByStatusCode(t *testing.T) {
require
.
True
(
t
,
ShouldDisableByStatusCode
(
500
))
require
.
True
(
t
,
ShouldDisableByStatusCode
(
500
))
require
.
False
(
t
,
ShouldDisableByStatusCode
(
200
))
require
.
False
(
t
,
ShouldDisableByStatusCode
(
200
))
}
}
func
TestShouldRetryByStatusCode
(
t
*
testing
.
T
)
{
orig
:=
AutomaticRetryStatusCodeRanges
t
.
Cleanup
(
func
()
{
AutomaticRetryStatusCodeRanges
=
orig
})
AutomaticRetryStatusCodeRanges
=
[]
StatusCodeRange
{
{
Start
:
429
,
End
:
429
},
{
Start
:
500
,
End
:
599
},
}
require
.
True
(
t
,
ShouldRetryByStatusCode
(
429
))
require
.
True
(
t
,
ShouldRetryByStatusCode
(
500
))
require
.
False
(
t
,
ShouldRetryByStatusCode
(
400
))
require
.
False
(
t
,
ShouldRetryByStatusCode
(
200
))
}
func
TestShouldRetryByStatusCode_DefaultMatchesLegacyBehavior
(
t
*
testing
.
T
)
{
require
.
False
(
t
,
ShouldRetryByStatusCode
(
200
))
require
.
False
(
t
,
ShouldRetryByStatusCode
(
400
))
require
.
True
(
t
,
ShouldRetryByStatusCode
(
401
))
require
.
False
(
t
,
ShouldRetryByStatusCode
(
408
))
require
.
True
(
t
,
ShouldRetryByStatusCode
(
429
))
require
.
True
(
t
,
ShouldRetryByStatusCode
(
500
))
require
.
False
(
t
,
ShouldRetryByStatusCode
(
504
))
require
.
False
(
t
,
ShouldRetryByStatusCode
(
524
))
require
.
True
(
t
,
ShouldRetryByStatusCode
(
599
))
}
web/src/components/settings/HttpStatusCodeRulesInput.jsx
0 → 100644
View file @
14d2290b
/*
Copyright (C) 2025 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import
React
from
'react'
;
import
{
Form
,
Tag
,
Typography
}
from
'@douyinfe/semi-ui'
;
export
default
function
HttpStatusCodeRulesInput
(
props
)
{
const
{
Text
}
=
Typography
;
const
{
label
,
field
,
placeholder
,
extraText
,
onChange
,
parsed
,
invalidText
,
}
=
props
;
return
(
<>
<
Form
.
Input
label=
{
label
}
placeholder=
{
placeholder
}
extraText=
{
extraText
}
field=
{
field
}
onChange=
{
onChange
}
/>
{
parsed
?.
ok
&&
parsed
.
tokens
?.
length
>
0
&&
(
<
div
style=
{
{
display
:
'flex'
,
flexWrap
:
'wrap'
,
gap
:
8
,
marginTop
:
8
,
}
}
>
{
parsed
.
tokens
.
map
((
token
)
=>
(
<
Tag
key=
{
token
}
size=
'small'
>
{
token
}
</
Tag
>
))
}
</
div
>
)
}
{
!
parsed
?.
ok
&&
(
<
Text
type=
'danger'
style=
{
{
display
:
'block'
,
marginTop
:
8
}
}
>
{
invalidText
}
{
parsed
?.
invalidTokens
&&
parsed
.
invalidTokens
.
length
>
0
?
`: ${parsed.invalidTokens.join(', ')}`
:
''
}
</
Text
>
)
}
</>
);
}
web/src/components/settings/OperationSetting.jsx
View file @
14d2290b
...
@@ -71,6 +71,7 @@ const OperationSetting = () => {
...
@@ -71,6 +71,7 @@ const OperationSetting = () => {
AutomaticEnableChannelEnabled
:
false
,
AutomaticEnableChannelEnabled
:
false
,
AutomaticDisableKeywords
:
''
,
AutomaticDisableKeywords
:
''
,
AutomaticDisableStatusCodes
:
'401'
,
AutomaticDisableStatusCodes
:
'401'
,
AutomaticRetryStatusCodes
:
'100-199,300-399,401-407,409-499,500-503,505-523,525-599'
,
'monitor_setting.auto_test_channel_enabled'
:
false
,
'monitor_setting.auto_test_channel_enabled'
:
false
,
'monitor_setting.auto_test_channel_minutes'
:
10
/* 签到设置 */
,
'monitor_setting.auto_test_channel_minutes'
:
10
/* 签到设置 */
,
'checkin_setting.enabled'
:
false
,
'checkin_setting.enabled'
:
false
,
...
...
web/src/i18n/locales/en.json
View file @
14d2290b
...
@@ -1925,6 +1925,8 @@
...
@@ -1925,6 +1925,8 @@
"自动禁用关键词"
:
"Automatic disable keywords"
,
"自动禁用关键词"
:
"Automatic disable keywords"
,
"自动禁用状态码"
:
"Auto-disable status codes"
,
"自动禁用状态码"
:
"Auto-disable status codes"
,
"自动禁用状态码格式不正确"
:
"Invalid auto-disable status code format"
,
"自动禁用状态码格式不正确"
:
"Invalid auto-disable status code format"
,
"自动重试状态码"
:
"Auto-retry status codes"
,
"自动重试状态码格式不正确"
:
"Invalid auto-retry status code format"
,
"支持填写单个状态码或范围(含首尾),使用逗号分隔"
:
"Supports single status codes or inclusive ranges; separate with commas"
,
"支持填写单个状态码或范围(含首尾),使用逗号分隔"
:
"Supports single status codes or inclusive ranges; separate with commas"
,
"例如:401, 403, 429, 500-599"
:
"e.g. 401,403,429,500-599"
,
"例如:401, 403, 429, 500-599"
:
"e.g. 401,403,429,500-599"
,
"自动选择"
:
"Auto Select"
,
"自动选择"
:
"Auto Select"
,
...
...
web/src/i18n/locales/zh.json
View file @
14d2290b
...
@@ -1911,6 +1911,8 @@
...
@@ -1911,6 +1911,8 @@
"自动禁用关键词"
:
"自动禁用关键词"
,
"自动禁用关键词"
:
"自动禁用关键词"
,
"自动禁用状态码"
:
"自动禁用状态码"
,
"自动禁用状态码"
:
"自动禁用状态码"
,
"自动禁用状态码格式不正确"
:
"自动禁用状态码格式不正确"
,
"自动禁用状态码格式不正确"
:
"自动禁用状态码格式不正确"
,
"自动重试状态码"
:
"自动重试状态码"
,
"自动重试状态码格式不正确"
:
"自动重试状态码格式不正确"
,
"支持填写单个状态码或范围(含首尾),使用逗号分隔"
:
"支持填写单个状态码或范围(含首尾),使用逗号分隔"
,
"支持填写单个状态码或范围(含首尾),使用逗号分隔"
:
"支持填写单个状态码或范围(含首尾),使用逗号分隔"
,
"例如:401, 403, 429, 500-599"
:
"例如:401,403,429,500-599"
,
"例如:401, 403, 429, 500-599"
:
"例如:401,403,429,500-599"
,
"自动选择"
:
"自动选择"
,
"自动选择"
:
"自动选择"
,
...
...
web/src/pages/Setting/Operation/SettingsMonitoring.jsx
View file @
14d2290b
...
@@ -24,8 +24,6 @@ import {
...
@@ -24,8 +24,6 @@ import {
Form
,
Form
,
Row
,
Row
,
Spin
,
Spin
,
Tag
,
Typography
,
}
from
'@douyinfe/semi-ui'
;
}
from
'@douyinfe/semi-ui'
;
import
{
import
{
compareObjects
,
compareObjects
,
...
@@ -34,13 +32,12 @@ import {
...
@@ -34,13 +32,12 @@ import {
showSuccess
,
showSuccess
,
showWarning
,
showWarning
,
parseHttpStatusCodeRules
,
parseHttpStatusCodeRules
,
verifyJSON
,
}
from
'../../../helpers'
;
}
from
'../../../helpers'
;
import
{
useTranslation
}
from
'react-i18next'
;
import
{
useTranslation
}
from
'react-i18next'
;
import
HttpStatusCodeRulesInput
from
'../../../components/settings/HttpStatusCodeRulesInput'
;
export
default
function
SettingsMonitoring
(
props
)
{
export
default
function
SettingsMonitoring
(
props
)
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
const
{
Text
}
=
Typography
;
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
inputs
,
setInputs
]
=
useState
({
const
[
inputs
,
setInputs
]
=
useState
({
ChannelDisableThreshold
:
''
,
ChannelDisableThreshold
:
''
,
...
@@ -49,6 +46,7 @@ export default function SettingsMonitoring(props) {
...
@@ -49,6 +46,7 @@ export default function SettingsMonitoring(props) {
AutomaticEnableChannelEnabled
:
false
,
AutomaticEnableChannelEnabled
:
false
,
AutomaticDisableKeywords
:
''
,
AutomaticDisableKeywords
:
''
,
AutomaticDisableStatusCodes
:
'401'
,
AutomaticDisableStatusCodes
:
'401'
,
AutomaticRetryStatusCodes
:
'100-199,300-399,401-407,409-499,500-503,505-523,525-599'
,
'monitor_setting.auto_test_channel_enabled'
:
false
,
'monitor_setting.auto_test_channel_enabled'
:
false
,
'monitor_setting.auto_test_channel_minutes'
:
10
,
'monitor_setting.auto_test_channel_minutes'
:
10
,
});
});
...
@@ -57,6 +55,9 @@ export default function SettingsMonitoring(props) {
...
@@ -57,6 +55,9 @@ export default function SettingsMonitoring(props) {
const
parsedAutoDisableStatusCodes
=
parseHttpStatusCodeRules
(
const
parsedAutoDisableStatusCodes
=
parseHttpStatusCodeRules
(
inputs
.
AutomaticDisableStatusCodes
||
''
,
inputs
.
AutomaticDisableStatusCodes
||
''
,
);
);
const
parsedAutoRetryStatusCodes
=
parseHttpStatusCodeRules
(
inputs
.
AutomaticRetryStatusCodes
||
''
,
);
function
onSubmit
()
{
function
onSubmit
()
{
const
updateArray
=
compareObjects
(
inputs
,
inputsRow
);
const
updateArray
=
compareObjects
(
inputs
,
inputsRow
);
...
@@ -69,16 +70,24 @@ export default function SettingsMonitoring(props) {
...
@@ -69,16 +70,24 @@ export default function SettingsMonitoring(props) {
:
''
;
:
''
;
return
showError
(
`
${
t
(
'自动禁用状态码格式不正确'
)}${
details
}
`
);
return
showError
(
`
${
t
(
'自动禁用状态码格式不正确'
)}${
details
}
`
);
}
}
if
(
!
parsedAutoRetryStatusCodes
.
ok
)
{
const
details
=
parsedAutoRetryStatusCodes
.
invalidTokens
&&
parsedAutoRetryStatusCodes
.
invalidTokens
.
length
>
0
?
`:
${
parsedAutoRetryStatusCodes
.
invalidTokens
.
join
(
', '
)}
`
:
''
;
return
showError
(
`
${
t
(
'自动重试状态码格式不正确'
)}${
details
}
`
);
}
const
requestQueue
=
updateArray
.
map
((
item
)
=>
{
const
requestQueue
=
updateArray
.
map
((
item
)
=>
{
let
value
=
''
;
let
value
=
''
;
if
(
typeof
inputs
[
item
.
key
]
===
'boolean'
)
{
if
(
typeof
inputs
[
item
.
key
]
===
'boolean'
)
{
value
=
String
(
inputs
[
item
.
key
]);
value
=
String
(
inputs
[
item
.
key
]);
}
else
{
}
else
{
if
(
item
.
key
===
'AutomaticDisableStatusCodes'
)
{
const
normalizedMap
=
{
value
=
parsedAutoDisableStatusCodes
.
normalized
;
AutomaticDisableStatusCodes
:
parsedAutoDisableStatusCodes
.
normalized
,
}
else
{
AutomaticRetryStatusCodes
:
parsedAutoRetryStatusCodes
.
normalized
,
value
=
inputs
[
item
.
key
]
;
}
;
}
value
=
normalizedMap
[
item
.
key
]
??
inputs
[
item
.
key
];
}
}
return
API
.
put
(
'/api/option/'
,
{
return
API
.
put
(
'/api/option/'
,
{
key
:
item
.
key
,
key
:
item
.
key
,
...
@@ -233,7 +242,7 @@ export default function SettingsMonitoring(props) {
...
@@ -233,7 +242,7 @@ export default function SettingsMonitoring(props) {
</
Row
>
</
Row
>
<
Row
gutter=
{
16
}
>
<
Row
gutter=
{
16
}
>
<
Col
xs=
{
24
}
sm=
{
16
}
>
<
Col
xs=
{
24
}
sm=
{
16
}
>
<
Form
.
Input
<
HttpStatusCodeRules
Input
label=
{
t
(
'自动禁用状态码'
)
}
label=
{
t
(
'自动禁用状态码'
)
}
placeholder=
{
t
(
'例如:401, 403, 429, 500-599'
)
}
placeholder=
{
t
(
'例如:401, 403, 429, 500-599'
)
}
extraText=
{
t
(
extraText=
{
t
(
...
@@ -243,35 +252,22 @@ export default function SettingsMonitoring(props) {
...
@@ -243,35 +252,22 @@ export default function SettingsMonitoring(props) {
onChange=
{
(
value
)
=>
onChange=
{
(
value
)
=>
setInputs
({
...
inputs
,
AutomaticDisableStatusCodes
:
value
})
setInputs
({
...
inputs
,
AutomaticDisableStatusCodes
:
value
})
}
}
parsed=
{
parsedAutoDisableStatusCodes
}
invalidText=
{
t
(
'自动禁用状态码格式不正确'
)
}
/>
/>
{
parsedAutoDisableStatusCodes
.
ok
&&
<
HttpStatusCodeRulesInput
parsedAutoDisableStatusCodes
.
tokens
.
length
>
0
&&
(
label=
{
t
(
'自动重试状态码'
)
}
<
div
placeholder=
{
t
(
'例如:401, 403, 429, 500-599'
)
}
style=
{
{
extraText=
{
t
(
display
:
'flex'
,
'支持填写单个状态码或范围(含首尾),使用逗号分隔'
,
flexWrap
:
'wrap'
,
gap
:
8
,
marginTop
:
8
,
}
}
>
{
parsedAutoDisableStatusCodes
.
tokens
.
map
((
token
)
=>
(
<
Tag
key=
{
token
}
size=
'small'
>
{
token
}
</
Tag
>
))
}
</
div
>
)
}
)
}
{
!
parsedAutoDisableStatusCodes
.
ok
&&
(
field=
{
'AutomaticRetryStatusCodes'
}
<
Text
type=
'danger'
style=
{
{
display
:
'block'
,
marginTop
:
8
}
}
>
onChange=
{
(
value
)
=>
{
t
(
'自动禁用状态码格式不正确'
)
}
setInputs
({
...
inputs
,
AutomaticRetryStatusCodes
:
value
})
{
parsedAutoDisableStatusCodes
.
invalidTokens
&&
}
parsedAutoDisableStatusCodes
.
invalidTokens
.
length
>
0
parsed=
{
parsedAutoRetryStatusCodes
}
?
`: ${parsedAutoDisableStatusCodes.invalidTokens.join(
invalidText=
{
t
(
'自动重试状态码格式不正确'
)
}
', ',
/>
)}`
:
''
}
</
Text
>
)
}
<
Form
.
TextArea
<
Form
.
TextArea
label=
{
t
(
'自动禁用关键词'
)
}
label=
{
t
(
'自动禁用关键词'
)
}
placeholder=
{
t
(
'一行一个,不区分大小写'
)
}
placeholder=
{
t
(
'一行一个,不区分大小写'
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment