diff --git a/controller/option.go b/controller/option.go index c82fbd7ead44..82ca43d3410a 100644 --- a/controller/option.go +++ b/controller/option.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" "one-api/common" + "one-api/middleware" "one-api/model" "one-api/setting" "strings" @@ -107,3 +108,26 @@ func UpdateOption(c *gin.Context) { }) return } + +// ToggleRequestLog 切换请求体日志的开关状态 +func ToggleRequestLog(c *gin.Context) { + var request struct { + Enable bool `json:"enable"` + } + if err := c.ShouldBindJSON(&request); err != nil { + c.JSON(200, gin.H{ + "success": false, + "message": "无效的请求参数", + }) + return + } + + middleware.EnableRequestBodyLogging = request.Enable + c.JSON(200, gin.H{ + "success": true, + "message": "请求体日志状态已更新", + "data": gin.H{ + "enable": middleware.EnableRequestBodyLogging, + }, + }) +} diff --git a/middleware/request-logger.go b/middleware/request-logger.go index cc672564b488..542250f22b37 100644 --- a/middleware/request-logger.go +++ b/middleware/request-logger.go @@ -11,6 +11,9 @@ import ( "github.com/gin-gonic/gin" ) +// EnableRequestBodyLogging 控制是否打印请求体 +var EnableRequestBodyLogging bool = false + func RequestLogger() gin.HandlerFunc { return func(c *gin.Context) { // 获取请求头 @@ -52,6 +55,24 @@ func RequestLogger() gin.HandlerFunc { formatMap(headers), ) + // 如果启用了请求体日志,则记录请求体 + if EnableRequestBodyLogging { + if c.Request.Method != "GET" { + body, err := io.ReadAll(c.Request.Body) + if err == nil { + // 尝试解析为JSON + var jsonBody interface{} + if err := json.Unmarshal(body, &jsonBody); err == nil { + logInfo += fmt.Sprintf("\tBody: %s", formatValue(jsonBody)) + } else { + logInfo += fmt.Sprintf("\tBody: %s", string(body)) + } + // 恢复请求体 + c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + } + } + } + common.SysLog(logInfo) c.Next() } @@ -84,7 +105,8 @@ func formatValue(v interface{}) string { if err != nil { return fmt.Sprintf("%v", v) } - return string(bytes) + // 去掉换行符 + return strings.ReplaceAll(string(bytes), "\n", "") } } @@ -94,7 +116,10 @@ func formatMapInterface(m map[string]interface{}) string { } var pairs []string for k, v := range m { - pairs = append(pairs, fmt.Sprintf("%s: %s", k, formatValue(v))) + // 处理值中的换行符 + valueStr := formatValue(v) + valueStr = strings.ReplaceAll(valueStr, "\n", "") + pairs = append(pairs, fmt.Sprintf("%s: %s", k, valueStr)) } return "{" + strings.Join(pairs, ", ") + "}" } @@ -105,7 +130,10 @@ func formatArray(arr []interface{}) string { } var elements []string for _, v := range arr { - elements = append(elements, formatValue(v)) + // 处理值中的换行符 + valueStr := formatValue(v) + valueStr = strings.ReplaceAll(valueStr, "\n", "") + elements = append(elements, valueStr) } return "[" + strings.Join(elements, ", ") + "]" } diff --git a/router/api-router.go b/router/api-router.go index ccef8c2c8a84..1701313bf8a8 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -77,6 +77,7 @@ func SetApiRouter(router *gin.Engine) { optionRoute.GET("/", controller.GetOptions) optionRoute.PUT("/", controller.UpdateOption) optionRoute.POST("/rest_model_ratio", controller.ResetModelRatio) + optionRoute.POST("/request_log", controller.ToggleRequestLog) } channelRoute := apiRouter.Group("/channel") channelRoute.Use(middleware.AdminAuth()) diff --git a/web/src/pages/Token/EditToken.js b/web/src/pages/Token/EditToken.js index aaafec642eea..74de4c0f64e5 100644 --- a/web/src/pages/Token/EditToken.js +++ b/web/src/pages/Token/EditToken.js @@ -205,6 +205,13 @@ const EditToken = (props) => { showError(t(message)); } } else { + // 验证分组是否已选择 + if (!inputs.group) { + showError(t('请选择令牌分组!')); + setLoading(false); + return; + } + // 处理新增多个令牌的情况 let successCount = 0; // 记录成功创建的令牌数量 for (let i = 0; i < tokenCount; i++) { @@ -446,12 +453,12 @@ const EditToken = (props) => { disabled={!model_limits_enabled} />
- {t('令牌分组,默认为用户的分组')} + {t('令牌分组(必选)')}
{groups.length > 0 ?