From 044e736a1b2025fe39453b09000e2c9dbff75ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E8=BF=AA=E6=96=87?= <3117675914@qq.com> Date: Wed, 3 Jun 2026 08:33:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20detectHTMLResponse=20=E8=B7=B3=E8=BF=87?= =?UTF-8?q?=20XML=20=E5=A3=B0=E6=98=8E=EF=BC=8C=E6=B7=BB=E5=8A=A0=20HTML?= =?UTF-8?q?=20=E5=93=8D=E5=BA=94=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 json.Unmarshal 之前检测 HTML 响应 - detectHTMLResponse 先 strip 声明再检查 HTML 前缀 - 返回中文诊断提示替代原始 JSON parse error - 修复 Code Review: TestDetectHTMLResponse/XML_声明后跟_HTML Co-Authored-By: Claude Opus 4.8 --- internal/client/client.go | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/internal/client/client.go b/internal/client/client.go index 1d20aed..98491e3 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -107,6 +107,18 @@ func (c *Client) Do(method, path string, body interface{}, query url.Values) (*o } } + // Detect HTML response (avoid returning login page as normal data) + if detectHTMLResponse(respData) { + msg := "服务器返回了 HTML 页面而非 JSON 数据" + suggestion := suggestHTMLFix() + return output.ErrorEnvelope(resp.StatusCode, msg, suggestion), + &APIError{ + StatusCode: resp.StatusCode, + Code: "HTML_RESPONSE", + Message: msg + "\n" + suggestion, + } + } + // Parse JSON var raw map[string]interface{} if err := json.Unmarshal(respData, &raw); err != nil { @@ -201,6 +213,41 @@ func (c *Client) Delete(path string, query url.Values) (*output.Envelope, error) return c.Do("DELETE", path, nil, query) } +// detectHTMLResponse detects whether the response body is an HTML page instead of JSON. +// It first strips any XML declaration () before checking for HTML prefixes. +func detectHTMLResponse(data []byte) bool { + trimmed := bytes.TrimSpace(data) + if len(trimmed) == 0 { + return false + } + // Skip leading XML declaration (e.g., ) + if bytes.HasPrefix(trimmed, []byte("")); idx != -1 { + trimmed = bytes.TrimSpace(trimmed[idx+2:]) + } + } + if len(trimmed) == 0 { + return false + } + // Check for HTML document prefixes + prefixes := []string{"