{"record":{"id":"bf4ecf9a702709f7","repo":"fish2018/pansou","slug":"s-api-w-bf4ecf","errorCode":null,"errorMessage":"[%s] 搜索 API 请求失败: %w","messagePattern":"\\[(.+?)\\] 搜索 API 请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/feikuai/feikuai.go","lineNumber":127,"sourceCode":"\tdefer cancel()\n\n\t// 创建请求\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建请求失败: %w\", p.Name(), err)\n\t}\n\n\t// 设置请求头\n\treq.Header.Set(\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\")\n\treq.Header.Set(\"Accept\", \"application/json, text/plain, */*\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Connection\", \"keep-alive\")\n\treq.Header.Set(\"Referer\", \"https://feikuai.tv/\")\n\n\t// 发送请求（带重试）\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn p.searchWeb(client, keyword, fmt.Errorf(\"[%s] 搜索 API 请求失败: %w\", p.Name(), err))\n\t}\n\tdefer resp.Body.Close()\n\n\t// 检查状态码\n\tif resp.StatusCode != 200 {\n\t\treturn p.searchWeb(client, keyword, fmt.Errorf(\"[%s] 搜索 API 返回状态码: %d\", p.Name(), resp.StatusCode))\n\t}\n\n\t// 读取并解析JSON响应\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn p.searchWeb(client, keyword, fmt.Errorf(\"[%s] 读取 API 响应失败: %w\", p.Name(), err))\n\t}\n\n\tvar apiResp FeikuaiAPIResponse\n\tif err := json.Unmarshal(body, &apiResp); err != nil {\n\t\treturn p.searchWeb(client, keyword, fmt.Errorf(\"[%s] API JSON 解析失败: %w\", p.Name(), err))\n\t}","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/feikuai/feikuai.go#L109-L145","documentation":"searchImpl sends the search API request through doRequestWithRetry; when even the retrying client fails, the plugin falls back to HTML search via searchWeb, attaching this wrapped error as the apiErr context. It means the JSON API endpoint was unreachable or errored.","triggerScenarios":"doRequestWithRetry returns non-nil (transport error, timeout, exhausted retries) for the API GET request.","commonSituations":"API domain blocked or DNS-poisoned, TLS errors after a site domain change, timeouts under DefaultTimeout, upstream API temporarily down.","solutions":["Inspect the wrapped cause from doRequestWithRetry","Confirm the API host resolves and is reachable (curl the searchURL)","Verify DefaultTimeout is generous enough for the upstream","Rely on/verify the searchWeb HTML fallback results"],"exampleFix":"// before\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    return p.searchWeb(client, keyword, fmt.Errorf(\"[%s] 搜索 API 请求失败: %w\", p.Name(), err))\n}\n// after\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    log.Printf(\"feikuai API request failed, falling back to web: %v\", err)\n    return p.searchWeb(client, keyword, fmt.Errorf(\"[%s] 搜索 API 请求失败: %w\", p.Name(), err))\n}","handlingStrategy":"fallback","validationCode":"// probe API endpoint before relying on it\nresp, err := client.Head(apiBaseURL)\n_ = err // if err != nil, expect searchWeb fallback path","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil && strings.Contains(err.Error(), \"搜索 API 请求失败\") {\n    log.Printf(\"feikuai API down, web fallback also attempted: %v\", err)\n    // surface partial info; the error already embeds the API cause\n}","preventionTips":["Treat API-down as normal and always keep the HTML fallback healthy","Monitor the fallback path's success rate separately","Rotate domain constants automatically when they stop resolving","Set realistic timeouts so transient slowness doesn't exhaust retries"],"tags":["http","api","fallback"],"backgroundTag":"api-request-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}