{"record":{"id":"fbcd789c6e98acd3","repo":"fish2018/pansou","slug":"url-d","errorCode":null,"errorMessage":"未获取到重定向URL，状态码: %d","messagePattern":"未获取到重定向URL，状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/qupanshe/qupanshe.go","lineNumber":302,"sourceCode":"\tif DebugLog {\n\t\tfmt.Printf(\"[qupanshe] Location header: %s\\n\", location)\n\t}\n\n\t// 读取响应体用于调试（非重定向状态码时）\n\tif resp.StatusCode != 302 && resp.StatusCode != 301 && DebugLog {\n\t\tbody, readErr := io.ReadAll(resp.Body)\n\t\tif readErr == nil {\n\t\t\tbodyStr := string(body)\n\t\t\tif len(bodyStr) > 1000 {\n\t\t\t\tfmt.Printf(\"[qupanshe] 响应体(前1000字符): %s\\n\", bodyStr[:1000])\n\t\t\t} else {\n\t\t\t\tfmt.Printf(\"[qupanshe] 响应体: %s\\n\", bodyStr)\n\t\t\t}\n\t\t}\n\t}\n\n\tif location == \"\" {\n\t\treturn \"\", fmt.Errorf(\"未获取到重定向URL，状态码: %d\", resp.StatusCode)\n\t}\n\n\t// 将相对路径转换为完整URL\n\tfullURL := BaseURL + \"/\" + strings.TrimPrefix(location, \"/\")\n\n\treturn fullURL, nil\n}\n\n// getSearchResults 获取搜索结果\nfunc (p *QupanshePlugin) getSearchResults(client *http.Client, searchURL, keyword string) ([]model.SearchResult, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n\tdefer cancel()\n\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"创建GET请求失败: %w\", err)\n\t}\n","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/qupanshe/qupanshe.go#L284-L320","documentation":"postSearchRequest expects the server to respond with a redirect (Location header) to the search results page. It collects the Location through the CheckRedirect callback; if the response ended with a non-redirect status and no Location was captured, it fails with this error including the final status code. It means the site's response shape did not match the expected redirect flow.","triggerScenarios":"The POST returned 200 (results inline or an error page), 4xx/5xx, or a login/captcha page instead of a 3xx redirect; the site removed the POST→redirect pattern; formhash was wrong causing the server to re-render the form.","commonSituations":"Target site redesigned its search endpoint; anti-bot protection returns 200 with a challenge; expired/invalid formhash; site rate-limits and returns 403/429 without redirect.","solutions":["Enable DebugLog to dump the final status code and response body to see what the server actually returned","Check whether the formhash (from getFormhash) was valid — an invalid token often causes a non-redirect response","Handle 200 responses by parsing results directly if the site no longer redirects","Update the expected redirect logic to the site's current behavior","Look for rate-limiting/captcha pages in the body and add backoff"],"exampleFix":"// before\nif location == \"\" {\n    return \"\", fmt.Errorf(\"未获取到重定向URL，状态码: %d\", resp.StatusCode)\n}\n// after\nif location == \"\" {\n    if resp.StatusCode == http.StatusOK {\n        return p.parseInlineResults(resp.Body) // site may now return results directly\n    }\n    return \"\", fmt.Errorf(\"未获取到重定向URL，状态码: %d\", resp.StatusCode)\n}","handlingStrategy":"fallback","validationCode":"// After the POST, verify a redirect actually occurred before expecting Location:\n// resp.StatusCode must be 301/302/303/307/308 for a Location to exist\nif resp.StatusCode >= 300 && resp.StatusCode < 400 && resp.Header.Get(\"Location\") == \"\" {\n    return fmt.Errorf(\"redirect without Location: %d\", resp.StatusCode)\n}","typeGuard":null,"tryCatchPattern":"_, err := plugin.Search(ctx, kw)\nif err != nil && strings.Contains(err.Error(), \"未获取到重定向URL\") {\n    // dump the response body via DebugLog and fall back to inline parsing or abort\n}","preventionTips":["Keep formhash fresh — stale tokens commonly break the redirect flow","Enable DebugLog in staging to capture unexpected response bodies","Update selectors/logic whenever the site's search flow changes","Respect rate limits so the server doesn't replace redirects with challenge pages"],"tags":["http","redirect","scraping","unexpected-response"],"backgroundTag":"unexpected-response-shape","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"}