{"record":{"id":"f10edf7cdd6dee73","repo":"fish2018/pansou","slug":"302-d","errorCode":null,"errorMessage":"期望302重定向，但得到状态码: %d","messagePattern":"期望302重定向，但得到状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/clxiong/clxiong.go","lineNumber":157,"sourceCode":"\t\tif lastErr == nil && (resp.StatusCode == 302 || resp.StatusCode == 301) {\n\t\t\tbreak\n\t\t}\n\t\tif resp != nil {\n\t\t\tresp.Body.Close()\n\t\t}\n\t\tif i < MaxRetries-1 {\n\t\t\ttime.Sleep(RetryDelay)\n\t\t}\n\t}\n\n\tif lastErr != nil {\n\t\treturn \"\", lastErr\n\t}\n\tdefer resp.Body.Close()\n\n\t// 检查重定向响应\n\tif resp.StatusCode != 302 && resp.StatusCode != 301 {\n\t\treturn \"\", fmt.Errorf(\"期望302重定向，但得到状态码: %d\", resp.StatusCode)\n\t}\n\n\t// 从Location头部提取searchid\n\tlocation := resp.Header.Get(\"Location\")\n\tif location == \"\" {\n\t\treturn \"\", fmt.Errorf(\"重定向响应中没有Location头部\")\n\t}\n\n\t// 解析searchid\n\tsearchID := p.extractSearchIDFromLocation(location)\n\tif searchID == \"\" {\n\t\treturn \"\", fmt.Errorf(\"无法从Location中提取searchid: %s\", location)\n\t}\n\n\tif p.debugMode {\n\t\tlog.Printf(\"[CLXIONG] 获取到searchid: %s\", searchID)\n\t}\n","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/clxiong/clxiong.go#L139-L175","documentation":"ClxiongPlugin.getSearchID expected the search POST to respond with an HTTP 301/302 redirect (the searchid is extracted from the Location header) but the server returned some other status. This breaks the plugin's core assumption about the site's two-step search flow. Common offending codes: 200 (site changed flow or serves an HTML challenge), 403 (blocked), 429 (rate limited), 5xx (server error).","triggerScenarios":"getSearchID's POST (after its retry loop succeeded in getting any response) receives resp.StatusCode not in {301, 302}; the function immediately returns \"期望302重定向，但得到状态码: %d\" to SearchWithResult, failing the whole search.","commonSituations":"clxiong deployed an anti-bot page or JS challenge answering 200 instead of redirecting; the client is rate limited (429) after rapid searches; blocked User-Agent yields 403; the site's search endpoint changed and now returns 404 or 200 with different semantics; server-side errors (500/503).","solutions":["Log the response body alongside the status code to see whether it's a CAPTCHA/challenge, rate-limit notice, or a changed flow.","If 403: update User-Agent/cookies/headers in getSearchID to mimic a browser.","If 429: implement backoff and reduce search frequency; honor Retry-After.","If 200 with HTML: the site changed its search flow — update getSearchID to extract the searchid from the new response (page HTML or a JSON API) instead of expecting a redirect.","If 5xx: retry later; consider adding 5xx handling to the retry loop."],"exampleFix":"// before\nif resp.StatusCode != 302 && resp.StatusCode != 301 {\n    return \"\", fmt.Errorf(\"期望302重定向，但得到状态码: %d\", resp.StatusCode)\n}\n// after\nif resp.StatusCode != 302 && resp.StatusCode != 301 {\n    snippet := \"\"\n    if b, e := io.ReadAll(io.LimitReader(resp.Body, 512)); e == nil { snippet = string(b) }\n    return \"\", fmt.Errorf(\"期望302重定向，但得到状态码: %d, body: %q\", resp.StatusCode, snippet)\n}","handlingStrategy":"fallback","validationCode":"// pre-flight: confirm the endpoint still redirects\nfunc stillRedirects(client *http.Client, postURL string, form url.Values) bool {\n    client.CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }\n    resp, err := client.PostForm(postURL, form)\n    if err != nil { return false }\n    defer resp.Body.Close()\n    return resp.StatusCode == 301 || resp.StatusCode == 302\n}","typeGuard":null,"tryCatchPattern":"searchID, err := p.getSearchID(keyword)\nif err != nil {\n    if strings.Contains(err.Error(), \"期望302重定向\") {\n        // site no longer redirects: switch to alternate extraction path\n        return p.searchViaHTMLFallback(keyword)\n    }\n    return nil, err\n}","preventionTips":["Configure CheckRedirect to NOT follow redirects so the Location header is observable.","Log response body snippets on unexpected statuses to distinguish CAPTCHA vs changed flow.","Refresh browser-like headers/cookies to avoid 403 blocks.","Add handling for 429/5xx in the retry loop instead of failing fast.","Pin an integration test that asserts the endpoint still returns 301/302."],"tags":["http","redirect","status-code","anti-bot","scraping"],"backgroundTag":"unexpected-http-status","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"}