发布 0.1.0:通知渠道、告警规则、令牌版本与安全加固
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
@@ -74,7 +77,7 @@ func (h *ociConfigHandler) create(c *gin.Context) {
|
||||
func (h *ociConfigHandler) list(c *gin.Context) {
|
||||
items, err := h.svc.List(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
respondError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, items)
|
||||
@@ -168,6 +171,7 @@ func (h *ociConfigHandler) update(c *gin.Context) {
|
||||
}
|
||||
|
||||
// @Summary 删除租户配置
|
||||
// @Description 删除租户配置及其本地关联任务、快照、回传、告警和 AI 渠道数据,并撤销 Webhook 密钥;不删除 OCI 云端资源。
|
||||
// @Tags 租户配置
|
||||
// @Param id path int true "配置 ID"
|
||||
// @Success 204 "无内容"
|
||||
@@ -258,17 +262,29 @@ func pathID(c *gin.Context) (uint, bool) {
|
||||
return uint(id), true
|
||||
}
|
||||
|
||||
// respondError 统一出错响应边界(S-08):OCI 服务错误经脱敏透出,记录缺失
|
||||
// 映射 404;其余按内部错误处理——响应只含固定文案与关联 ID,完整原因
|
||||
// (可能携带 SQL / DSN / 路径等内部细节)仅写服务端日志,经同一 ID 对应。
|
||||
func respondError(c *gin.Context, err error) {
|
||||
status := http.StatusInternalServerError
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
status = http.StatusNotFound
|
||||
}
|
||||
var svcErr common.ServiceError
|
||||
if errors.As(err, &svcErr) {
|
||||
respondOCIError(c, err, svcErr)
|
||||
return
|
||||
}
|
||||
c.JSON(status, gin.H{"error": err.Error()})
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "资源不存在"})
|
||||
return
|
||||
}
|
||||
id := newRequestID()
|
||||
log.Printf("[ERR %s] %s %s: %v", id, c.Request.Method, requestPath(c), err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "服务器内部错误", "requestId": id})
|
||||
}
|
||||
|
||||
// newRequestID 生成错误关联 ID(8 字节随机 hex),响应与服务端日志据此对应。
|
||||
func newRequestID() string {
|
||||
b := make([]byte, 8)
|
||||
_, _ = rand.Read(b)
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
// respondOCIError 提炼 OCI 服务错误:透传 HTTP 状态码,
|
||||
@@ -278,9 +294,10 @@ func respondOCIError(c *gin.Context, err error, svcErr common.ServiceError) {
|
||||
if status < http.StatusBadRequest {
|
||||
status = http.StatusBadGateway
|
||||
}
|
||||
// 面板的 401 专属本地 JWT 失效(前端收到即登出);
|
||||
// 上游 OCI 的 401 是代理调用被拒,改用 502 透出
|
||||
if status == http.StatusUnauthorized {
|
||||
// 面板的 401 专属本地 JWT 失效(前端收到即登出)、429 专属本地 IP 限速
|
||||
// (前端收到即跳 /blocked);上游 OCI 的同码是代理调用被拒/云端限流,
|
||||
// 均改用 502 透出,body 保留 ociCode 供辨识
|
||||
if status == http.StatusUnauthorized || status == http.StatusTooManyRequests {
|
||||
status = http.StatusBadGateway
|
||||
}
|
||||
body := gin.H{
|
||||
|
||||
Reference in New Issue
Block a user