{"record":{"id":"b872b8021d162bef","repo":"fish2018/pansou","slug":"s-api-s-code-d","errorCode":null,"errorMessage":"[%s] API 返回错误: %s (code: %d)","messagePattern":"\\[(.+?)\\] API 返回错误: (.+?) \\(code: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/feikuai/feikuai.go","lineNumber":149,"sourceCode":"\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}\n\n\t// 检查API响应状态\n\tif apiResp.Code != 0 {\n\t\treturn p.searchWeb(client, keyword, fmt.Errorf(\"[%s] API 返回错误: %s (code: %d)\", p.Name(), apiResp.Msg, apiResp.Code))\n\t}\n\n\t// 解析搜索结果\n\tvar results []model.SearchResult\n\tfor _, item := range apiResp.Items {\n\t\t// 每个item可能包含多个种子\n\t\tfor _, torrent := range item.Torrents {\n\t\t\tresult := p.parseTorrent(keyword, item, torrent)\n\t\t\tif result.Title != \"\" && len(result.Links) > 0 {\n\t\t\t\tresults = append(results, result)\n\t\t\t}\n\t\t}\n\t}\n\n\t// 使用关键词过滤结果\n\treturn plugin.FilterResultsByKeyword(results, keyword), nil\n}\n","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/feikuai/feikuai.go#L131-L167","documentation":"The Feikuai API uses an application-level code field; when the JSON decodes fine but apiResp.Code != 0, searchImpl treats it as a business-logic error, includes apiResp.Msg and the code, and falls back to HTML search. The HTTP layer succeeded but the API itself reported an error.","triggerScenarios":"apiResp.Code != 0 in the decoded FeikuaiAPIResponse — e.g. invalid query parameters, banned keyword, account/IP throttling reported in-body.","commonSituations":"Upstream API contract change redefining success codes, empty or malformed keyword triggering an in-body error, IP throttled by the service.","solutions":["Read apiResp.Msg and the numeric code to determine the API-specific cause","Check the upstream API docs for current success code convention","Sanitize/validate the keyword before querying","Fall back to searchWeb results as designed"],"exampleFix":"// before\nif apiResp.Code != 0 {\n    return p.searchWeb(client, keyword, fmt.Errorf(\"[%s] API 返回错误: %s (code: %d)\", p.Name(), apiResp.Msg, apiResp.Code))\n}\n// after\nif apiResp.Code != 0 {\n    log.Printf(\"feikuai API business error code=%d msg=%s keyword=%q\", apiResp.Code, apiResp.Msg, keyword)\n    return p.searchWeb(client, keyword, fmt.Errorf(\"[%s] API 返回错误: %s (code: %d)\", p.Name(), apiResp.Msg, apiResp.Code))\n}","handlingStrategy":"fallback","validationCode":"// validate keyword before calling the API\nif strings.TrimSpace(keyword) == \"\" { return nil, fmt.Errorf(\"empty keyword\") }\nif len([]rune(keyword)) > 100 { return nil, fmt.Errorf(\"keyword too long\") }","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword)\nif err != nil {\n    var apiErr *apiBusinessError // if exported\n    if errors.As(err, &apiErr) && apiErr.Code != 0 {\n        log.Printf(\"feikuai API rejected query: code=%d msg=%s\", apiErr.Code, apiErr.Msg)\n        // rely on web-scrape fallback or other plugins\n    }\n}","preventionTips":["Read and log apiResp.Msg — it usually names the exact problem","Sanitize keywords (strip banned characters) before querying","Keep an in-body success-code check up to date with the API contract","Never treat HTTP 200 + code!=0 as success"],"tags":["api","business-error","fallback"],"backgroundTag":"api-error-response","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"}