Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
a1540e27
"vscode:/vscode.git/clone" did not exist on "900cce20a1d5453aecfa3a2d59bcd662fa3ec9f7"
Commit
a1540e27
authored
Dec 31, 2025
by
Wei Shaw
Browse files
feat: 修复 OpenAI 402 报错自动切换问题
parent
b7c6d040
Changes
3
Hide whitespace changes
Inline
Side-by-side
backend/internal/service/openai_gateway_service.go
View file @
a1540e27
...
...
@@ -240,7 +240,7 @@ func (s *OpenAIGatewayService) GetAccessToken(ctx context.Context, account *Acco
func
(
s
*
OpenAIGatewayService
)
shouldFailoverUpstreamError
(
statusCode
int
)
bool
{
switch
statusCode
{
case
401
,
403
,
429
,
529
:
case
401
,
402
,
403
,
429
,
529
:
return
true
default
:
return
statusCode
>=
500
...
...
@@ -454,6 +454,10 @@ func (s *OpenAIGatewayService) handleErrorResponse(ctx context.Context, resp *ht
statusCode
=
http
.
StatusBadGateway
errType
=
"upstream_error"
errMsg
=
"Upstream authentication failed, please contact administrator"
case
402
:
statusCode
=
http
.
StatusBadGateway
errType
=
"upstream_error"
errMsg
=
"Upstream payment required: insufficient balance or billing issue"
case
403
:
statusCode
=
http
.
StatusBadGateway
errType
=
"upstream_error"
...
...
backend/internal/service/ratelimit_service.go
View file @
a1540e27
...
...
@@ -39,6 +39,10 @@ func (s *RateLimitService) HandleUpstreamError(ctx context.Context, account *Acc
// 认证失败:停止调度,记录错误
s
.
handleAuthError
(
ctx
,
account
,
"Authentication failed (401): invalid or expired credentials"
)
return
true
case
402
:
// 支付要求:余额不足或计费问题,停止调度
s
.
handleAuthError
(
ctx
,
account
,
"Payment required (402): insufficient balance or billing issue"
)
return
true
case
403
:
// 禁止访问:停止调度,记录错误
s
.
handleAuthError
(
ctx
,
account
,
"Access forbidden (403): account may be suspended or lack permissions"
)
...
...
frontend/src/components/common/Modal.vue
0 → 100755
View file @
a1540e27
<
template
>
<Teleport
to=
"body"
>
<div
v-if=
"show"
class=
"modal-overlay"
aria-labelledby=
"modal-title"
role=
"dialog"
aria-modal=
"true"
@
click.self=
"handleClose"
>
<!-- Modal panel -->
<div
:class=
"['modal-content', sizeClasses]"
@
click.stop
>
<!-- Header -->
<div
class=
"modal-header"
>
<h3
id=
"modal-title"
class=
"modal-title"
>
{{
title
}}
</h3>
<button
@
click=
"emit('close')"
class=
"-mr-2 rounded-xl p-2 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 dark:text-dark-500 dark:hover:bg-dark-700 dark:hover:text-dark-300"
aria-label=
"Close modal"
>
<svg
class=
"h-5 w-5"
fill=
"none"
stroke=
"currentColor"
viewBox=
"0 0 24 24"
stroke-width=
"1.5"
>
<path
stroke-linecap=
"round"
stroke-linejoin=
"round"
d=
"M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<!-- Body -->
<div
class=
"modal-body"
>
<slot></slot>
</div>
<!-- Footer -->
<div
v-if=
"$slots.footer"
class=
"modal-footer"
>
<slot
name=
"footer"
></slot>
</div>
</div>
</div>
</Teleport>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
computed
,
watch
,
onMounted
,
onUnmounted
}
from
'
vue
'
type
ModalSize
=
'
sm
'
|
'
md
'
|
'
lg
'
|
'
xl
'
|
'
2xl
'
|
'
full
'
interface
Props
{
show
:
boolean
title
:
string
size
?:
ModalSize
closeOnEscape
?:
boolean
closeOnClickOutside
?:
boolean
}
interface
Emits
{
(
e
:
'
close
'
):
void
}
const
props
=
withDefaults
(
defineProps
<
Props
>
(),
{
size
:
'
md
'
,
closeOnEscape
:
true
,
closeOnClickOutside
:
false
})
const
emit
=
defineEmits
<
Emits
>
()
const
sizeClasses
=
computed
(()
=>
{
const
sizes
:
Record
<
ModalSize
,
string
>
=
{
sm
:
'
max-w-sm
'
,
md
:
'
max-w-md
'
,
lg
:
'
max-w-lg
'
,
xl
:
'
max-w-xl
'
,
'
2xl
'
:
'
max-w-5xl
'
,
full
:
'
max-w-4xl
'
}
return
sizes
[
props
.
size
]
})
const
handleClose
=
()
=>
{
if
(
props
.
closeOnClickOutside
)
{
emit
(
'
close
'
)
}
}
const
handleEscape
=
(
event
:
KeyboardEvent
)
=>
{
if
(
props
.
show
&&
props
.
closeOnEscape
&&
event
.
key
===
'
Escape
'
)
{
emit
(
'
close
'
)
}
}
// Prevent body scroll when modal is open
watch
(
()
=>
props
.
show
,
(
isOpen
)
=>
{
console
.
log
(
'
[Modal] show changed to:
'
,
isOpen
)
if
(
isOpen
)
{
document
.
body
.
style
.
overflow
=
'
hidden
'
}
else
{
document
.
body
.
style
.
overflow
=
''
}
},
{
immediate
:
true
}
)
onMounted
(()
=>
{
document
.
addEventListener
(
'
keydown
'
,
handleEscape
)
})
onUnmounted
(()
=>
{
document
.
removeEventListener
(
'
keydown
'
,
handleEscape
)
document
.
body
.
style
.
overflow
=
''
})
</
script
>
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