{"record":{"id":"6645be1e3e5f42fc","repo":"fish2018/pansou","slug":"s-d-6645be","errorCode":null,"errorMessage":"[%s] 搜索返回状态码: %d","messagePattern":"\\[(.+?)\\] 搜索返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/duanjuw/duanjuw.go","lineNumber":121,"sourceCode":"\n\tsearchURL := fmt.Sprintf(duanjuwSearchURL, url.QueryEscape(keyword))\n\tctx, cancel := context.WithTimeout(context.Background(), duanjuwSearchTimeout)\n\tdefer cancel()\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建搜索请求失败: %w\", p.Name(), err)\n\t}\n\tsetDuanjuwHeaders(req, duanjuwBaseURL+\"/\")\n\n\tresp, err := doDuanjuwRequestWithRetry(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 != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果失败: %w\", p.Name(), err)\n\t}\n\n\titems := p.parseSearchResults(doc)\n\tif len(items) == 0 {\n\t\treturn []model.SearchResult{}, nil\n\t}\n\t// The current site renders search results as numbered chat entries with\n\t// direct pan links. Older pages still use result cards and need detail fetches.\n\tfor _, item := range items {\n\t\tif len(item.Links) > 0 {\n\t\t\treturn plugin.FilterResultsByKeyword(items, keyword), nil\n\t\t}\n\t}","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/duanjuw/duanjuw.go#L103-L139","documentation":"The duanjuw plugin returns this when the search response status code is not 200. Any non-OK status (403 WAF block, 429 rate limit, 5xx) is treated as a failed search since the plugin expects an HTML results page.","triggerScenarios":"doDuanjuwRequestWithRetry succeeded at transport level but resp.StatusCode != http.StatusOK in searchImpl.","commonSituations":"Anti-bot protection blocking datacenter IPs; too-frequent searches hitting a rate limit; site returning 5xx during incidents; redirect to a login or verification page.","solutions":["Map the status: 403 → blocked, change headers/cookies/IP; 429 → back off and slow down; 5xx → retry later","Verify setDuanjuwHeaders produces browser-like Referer and User-Agent","Reduce search frequency or add caching for repeated keywords","Re-check the site manually; if it now requires JS challenge, the plugin needs updating"],"exampleFix":"// before\nif err != nil { return err }\n// after\nvar statusErr interface{ Error() string }\nif strings.Contains(err.Error(), \"搜索返回状态码: 429\") {\n    time.Sleep(time.Minute)\n    items, err = p.searchImpl(k)\n}","handlingStrategy":"fallback","validationCode":"// probe status before searches\nresp, err := client.Get(duanjuwBaseURL + \"/\")\nif err == nil {\n    if resp.StatusCode == 403 || resp.StatusCode == 429 { log.Println(\"currently blocked/rate-limited\") }\n    resp.Body.Close()\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"搜索返回状态码: 429\") {\n    select {\n    case <-time.After(time.Minute):\n        return p.searchImpl(k)\n    case <-ctx.Done():\n        return ctx.Err()\n    }\n}","preventionTips":["Throttle search frequency; cache repeated keywords","Rotate User-Agent/cookies when 403s appear","Differentiate backoff by status code family","Watch for JS-challenge redirects indicating WAF changes"],"tags":["http","http-status","search"],"backgroundTag":"http-non-200-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"}