{"record":{"id":"a3a428d63fea2498","repo":"fish2018/pansou","slug":"s-http-d-a3a428","errorCode":null,"errorMessage":"[%s] 搜索请求HTTP状态错误: %d","messagePattern":"\\[(.+?)\\] 搜索请求HTTP状态错误: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/hdmoli/hdmoli.go","lineNumber":140,"sourceCode":"\t}\n\n\t// 设置完整的请求头\n\treq.Header.Set(\"User-Agent\", UserAgent)\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\")\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(\"Upgrade-Insecure-Requests\", \"1\")\n\treq.Header.Set(\"Cache-Control\", \"max-age=0\")\n\treq.Header.Set(\"Referer\", BaseURL+\"/\") // HDmoli需要设置referer\n\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求HTTP状态错误: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\t// 解析HTML提取搜索结果\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果HTML失败: %w\", p.Name(), err)\n\t}\n\n\treturn p.parseSearchResults(doc)\n}\n\n// doRequestWithRetry 带重试机制的HTTP请求\nfunc (p *HdmoliPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {\n\tmaxRetries := 3\n\tvar lastErr error\n\n\tfor i := 0; i < maxRetries; i++ {\n\t\tif i > 0 {","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/hdmoli/hdmoli.go#L122-L158","documentation":"Status error in hdmoli's executeSearch (plugin/hdmoli/hdmoli.go:140): the search request succeeded at transport level but returned a non-200 status after retries. Note this record's message at the throw site is the wrapped '搜索请求失败: %w' from doRequestWithRetry; the status-check path reports the HTTP code, indicating the site refused or rate-limited the search.","triggerScenarios":"The server replies 403/429 (anti-bot or rate limiting), 404 (search path changed), 5xx (server error), or 301/302 that were not followed by the client.","commonSituations":"缺少 Referer 触发防盗链；高频搜索被限流。","solutions":["Log the status code and response body snippet to see what the server returned","For 403/429: slow down request rate, rotate User-Agent, or obtain needed cookies","For 404: update the plugin's search path to the site's current URL structure","Ensure CheckRedirect is enabled and redirect responses are followed"],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] 搜索请求HTTP状态错误: %d\", p.Name(), resp.StatusCode)\n}\n// after\nif resp.StatusCode != 200 {\n    body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))\n    return nil, fmt.Errorf(\"[%s] 搜索请求HTTP状态错误: %d, body: %s\", p.Name(), resp.StatusCode, body)\n}","handlingStrategy":"retry","validationCode":"// Go: inspect status before treating as failure\nif resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusTooManyRequests {\n    time.Sleep(backoff) // honor rate limiting before retrying\n}","typeGuard":null,"tryCatchPattern":"if resp.StatusCode != 200 {\n    body, _ := io.ReadAll(io.LimitReader(resp.Body, 256))\n    log.Printf(\"hdmoli status %d: %s\", resp.StatusCode, body)\n    // branch on code: 403/429 => backoff & rotate UA; 404 => update URL\n}","preventionTips":["Send browser-like headers (UA, Accept, Referer) to reduce 403s","Rate-limit requests to avoid 429","Update selectors/URL paths when the site is redesigned","Log response bodies on unexpected statuses"],"tags":["go","http","status-code","web-scraping"],"backgroundTag":"http-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"}