{"record":{"id":"535e3a7b7990d0f4","repo":"fish2018/pansou","slug":"s-535e3a","errorCode":null,"errorMessage":"不支持的请求方法: %s","messagePattern":"不支持的请求方法: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/gying/gying.go","lineNumber":1919,"sourceCode":"\treturn nil\n}\n\nfunc (p *GyingPlugin) requestWithChallengeRetry(scraper *cloudscraper.Scraper, method, requestURL, contentType, requestBody string) ([]byte, int, http.Header, error) {\n\tfor attempt := 0; attempt < 2; attempt++ {\n\t\tvar (\n\t\t\tresp *http.Response\n\t\t\terr  error\n\t\t)\n\n\t\tswitch method {\n\t\tcase http.MethodGet:\n\t\t\t// Use cloudscraper for GET as well as POST so the challenge page,\n\t\t\t// verification request, and retry share the same browser-like headers.\n\t\t\tresp, err = scraper.Get(requestURL)\n\t\tcase http.MethodPost:\n\t\t\tresp, err = scraper.Post(requestURL, contentType, strings.NewReader(requestBody))\n\t\tdefault:\n\t\t\treturn nil, 0, nil, fmt.Errorf(\"不支持的请求方法: %s\", method)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, 0, nil, err\n\t\t}\n\n\t\tstatusCode := resp.StatusCode\n\t\theaders := resp.Header.Clone()\n\t\tbody, readErr := ioutil.ReadAll(resp.Body)\n\t\tresp.Body.Close()\n\t\tif readErr != nil {\n\t\t\treturn nil, statusCode, headers, readErr\n\t\t}\n\n\t\tif DebugLog {\n\t\t\tfmt.Printf(\"[Gying] requestWithChallengeRetry: method=%s attempt=%d status=%d url=%s bodyLen=%d challenge=%v loginShell=%v\\n\",\n\t\t\t\tmethod, attempt+1, statusCode, requestURL, len(body), isBotChallengePage(body), isLoginShell(body))\n\t\t}\n","sourceCodeStart":1901,"sourceCodeEnd":1937,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/gying/gying.go#L1901-L1937","documentation":"requestWithChallengeRetry only supports GET and POST for its cloudscraper-backed retry loop; any other HTTP method reaches the default branch and is rejected. This is a deliberate capability limit of the challenge-retry wrapper.","triggerScenarios":"Calling the plugin's request path (requestWithChallengeRetry) with method set to e.g. http.MethodPut, DELETE, PATCH, or HEAD.","commonSituations":"Caller code generating dynamic HTTP methods (REST clients) passed through the plugin, or upstream code changed from GET/POST to another verb.","solutions":["Use GET or POST for requests routed through the challenge-retry wrapper.","Extend the switch with a scraper.Do(...) case for other verbs if you control the code.","Route non-GET/POST requests through a plain HTTP client outside the challenge logic if the endpoint doesn't need anti-bot handling."],"exampleFix":"// before\nclient.Do(req) // method=PUT hits default branch\n// after\nreq.Method = http.MethodPost // or add a case for PUT backed by scraper\nresp, err = scraper.Post(requestURL, contentType, strings.NewReader(requestBody))","handlingStrategy":"validation","validationCode":"if method != http.MethodGet && method != http.MethodPost { return fmt.Errorf(\"challenge-retry path supports only GET/POST, got %s\", method) }","typeGuard":null,"tryCatchPattern":"if err != nil { if strings.Contains(err.Error(), \"不支持的请求方法\") { http.Error(w, \"method not allowed\", http.StatusMethodNotAllowed) } }","preventionTips":["Restrict callers to GET/POST for this code path","Normalize verbs (e.g. PUT-with-body) to POST upstream","Document the supported method surface","Return 405 semantics to end users"],"tags":["http-method","unsupported-operation","cloudscraper"],"backgroundTag":"unsupported-operation","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"}