{"record":{"id":"3dcb6bcefea856a8","repo":"fish2018/pansou","slug":"s-3dcb6b","errorCode":null,"errorMessage":"[%s] 请求被限流","messagePattern":"\\[(.+?)\\] 请求被限流","errorType":"http","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"plugin/yuhuage/yuhuage.go","lineNumber":109,"sourceCode":"\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(\"Referer\", BaseURL+\"/\")\n\t\n\t// 发送HTTP请求\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\t\n\tif resp.StatusCode == 429 {\n\t\tatomic.StoreInt32(&p.rateLimited, 1)\n\t\tgo func() {\n\t\t\ttime.Sleep(60 * time.Second)\n\t\t\tatomic.StoreInt32(&p.rateLimited, 0)\n\t\t}()\n\t\treturn nil, fmt.Errorf(\"[%s] 请求被限流\", p.Name())\n\t}\n\t\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] HTTP错误: %d\", p.Name(), resp.StatusCode)\n\t}\n\t\n\t// 读取响应\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取响应失败: %w\", p.Name(), err)\n\t}\n\t\n\t// 解析搜索结果\n\tresults, err := p.parseSearchResults(string(body))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/yuhuage/yuhuage.go#L91-L127","documentation":"The yuhuage upstream returned HTTP 429 Too Many Requests. searchImpl sets the rateLimited flag for 60 seconds (subsequent searches fail fast with \"rate limited\") and returns \"[%s] 请求被限流\" for the current call. It signals the site is actively throttling this client.","triggerScenarios":"A search request completed and resp.StatusCode == 429; triggered by sending too many requests in a short window from the same IP.","commonSituations":"Bursty search traffic from many users; multiple pansou instances sharing one outbound IP; the site tightened its rate limits.","solutions":["Back off — the plugin already pauses new searches for 60s; avoid hammering retries meanwhile.","Reduce request concurrency or add a global rate limiter in front of the plugin.","Distribute outbound traffic across proxies/IPs if volume is legitimately high.","Skip this plugin for the throttle window in aggregation logic instead of surfacing errors to users."],"exampleFix":"// before\nif resp.StatusCode == 429 {\n    atomic.StoreInt32(&p.rateLimited, 1)\n    go func() {\n        time.Sleep(60 * time.Second)\n        atomic.StoreInt32(&p.rateLimited, 0)\n    }()\n    return nil, fmt.Errorf(\"[%s] 请求被限流\", p.Name())\n}\n// after\nif resp.StatusCode == 429 {\n    atomic.StoreInt32(&p.rateLimited, 1)\n    if retryAfter := resp.Header.Get(\"Retry-After\"); retryAfter != \"\" {\n        if secs, e := strconv.Atoi(retryAfter); e == nil && secs > 0 && secs <= 600 {\n            rateLimitResetAt = time.Now().Add(time.Duration(secs) * time.Second)\n        }\n    }\n    return nil, fmt.Errorf(\"[%s] 请求被限流\", p.Name())\n}","handlingStrategy":"retry","validationCode":"// Pace calls proactively to avoid 429:\nif time.Since(lastCall) < 1*time.Second {\n    time.Sleep(time.Second - time.Since(lastCall))\n}","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword, ext)\nif err != nil {\n    if strings.Contains(err.Error(), \"请求被限流\") {\n        time.Sleep(65 * time.Second)\n        results, err = plugin.Search(keyword, ext)\n    }\n}","preventionTips":["Respect the 60s cooldown; don't retry immediately after 429.","Add a global rate limiter in front of the plugin.","Honor Retry-After semantics if you add them client-side."],"tags":["rate-limit","http-429","throttling"],"backgroundTag":"rate-limit-exceeded","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"}