Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// parseFailureSnippetLen bounds the head/tail snippets logged on body parse
|
||||
// failure. 256 bytes is enough to see the structural context (model field,
|
||||
// first content block / trailing brace) without dumping user payloads.
|
||||
const parseFailureSnippetLen = 256
|
||||
|
||||
// logRequestBodyParseFailure records the real reason a request body failed
|
||||
// JSON parsing/validation. The client keeps receiving the generic
|
||||
// "Failed to parse request body"; the sanitized diagnostics (underlying
|
||||
// error with byte offset, body length, escaped head/tail snippets) land in
|
||||
// the server log only, so operators can distinguish genuinely invalid JSON
|
||||
// from a truncated or partially consumed body.
|
||||
//
|
||||
// err may be nil for call sites that validate with gjson.ValidBytes directly;
|
||||
// the diagnostic error is derived from the body in that case.
|
||||
func logRequestBodyParseFailure(reqLog *zap.Logger, body []byte, err error) {
|
||||
if reqLog == nil {
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
err = service.DescribeInvalidJSON(body)
|
||||
}
|
||||
|
||||
head := body
|
||||
var tail []byte
|
||||
if len(body) > parseFailureSnippetLen {
|
||||
head = body[:parseFailureSnippetLen]
|
||||
tail = body[len(body)-parseFailureSnippetLen:]
|
||||
}
|
||||
|
||||
fields := []zap.Field{
|
||||
zap.Error(err),
|
||||
zap.Int("body_len", len(body)),
|
||||
zap.String("body_head", sanitizeBodySnippet(head)),
|
||||
}
|
||||
if len(tail) > 0 {
|
||||
fields = append(fields, zap.String("body_tail", sanitizeBodySnippet(tail)))
|
||||
}
|
||||
reqLog.Warn("parse request body failed", fields...)
|
||||
}
|
||||
|
||||
// sanitizeBodySnippet escapes control characters and invalid UTF-8 so the
|
||||
// snippet is always a single printable log line.
|
||||
func sanitizeBodySnippet(b []byte) string {
|
||||
return strconv.Quote(string(b))
|
||||
}
|
||||
Reference in New Issue
Block a user