{"record":{"id":"c24ee763fec2ac67","repo":"fish2018/pansou","slug":"d-w-c24ee7","errorCode":null,"errorMessage":"重试 %d 次后仍然失败: %w","messagePattern":"重试 (.+?) 次后仍然失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/cyg/cyg.go","lineNumber":399,"sourceCode":"\n\t\t// 克隆请求避免并发问题\n\t\treqClone := req.Clone(req.Context())\n\n\t\tresp, err := client.Do(reqClone)\n\t\tif err == nil && resp.StatusCode == 200 {\n\t\t\treturn resp, nil\n\t\t}\n\n\t\tif resp != nil {\n\t\t\tresp.Body.Close()\n\t\t}\n\t\tlastErr = err\n\t\tif err == nil {\n\t\t\tlastErr = fmt.Errorf(\"HTTP 状态码 %d\", resp.StatusCode)\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"重试 %d 次后仍然失败: %w\", maxRetries, lastErr)\n}\n\n// parseExtOptions 从ext参数中解析搜索选项\nfunc (p *CygPlugin) parseExtOptions(ext map[string]interface{}) CygSearchOptions {\n\topts := CygSearchOptions{\n\t\tPerPage: 20,\n\t\tPage:    1,\n\t\tOrderBy: \"date\",\n\t\tOrder:   \"desc\",\n\t}\n\n\tif ext == nil {\n\t\treturn opts\n\t}\n\n\tif perPage, ok := ext[\"per_page\"].(int); ok && perPage > 0 {\n\t\topts.PerPage = perPage\n\t}","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/cyg/cyg.go#L381-L417","documentation":"doRequestWithRetry exhausts maxRetries attempts without a successful response and returns \"重试 %d 次后仍然失败\" wrapping the last error (either a transport error or the synthesized \"HTTP 状态码 %d\"). It signals the caller that the request failed permanently after all retries.","triggerScenarios":"fetchSearchResults or getDownloadLinks issues a request that fails on every attempt: persistent network outage, site hard-blocking the client, sustained 5xx, or retries exhausted faster than the outage lasted.","commonSituations":"Site is down for maintenance, IP rate-limited/banned across the whole retry window, corporate proxy blocking the domain, or maxRetries too low for a flaky connection.","solutions":["Unwrap the cause (errors.Unwrap) to distinguish transport failure from a bad HTTP status.","Increase maxRetries and add exponential backoff with jitter between attempts.","Verify reachability of the target host (curl/DNS) and check for proxy/firewall blocking.","If 403/429 persist, rotate User-Agent/cookies or respect rate limits before retrying.","Surface the error to the user as 'source temporarily unavailable' and allow the caller to retry later."],"exampleFix":"// before\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    return nil, err\n}\n// after\nresp, err := p.doRequestWithRetry(req, client)\nif err != nil {\n    return nil, fmt.Errorf(\"source unavailable after retries: %w\", err) // caller can retry later\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(ctx, keyword)\nif err != nil {\n    if strings.Contains(err.Error(), \"重试\") {\n        // all retries exhausted — schedule a later retry with backoff\n        return nil, fmt.Errorf(\"source temporarily unavailable: %w\", err)\n    }\n    return nil, err\n}","preventionTips":["Configure sufficient retries with exponential backoff plus jitter.","Check host reachability (DNS, firewall, proxy) before blaming the plugin.","Rate-limit your own requests to avoid triggering site-side bans that outlast the retry window."],"tags":["http","retry","go","network"],"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"}