{"record":{"id":"dcb8d69e4de05412","repo":"fish2018/pansou","slug":"s-w-dcb8d6","errorCode":null,"errorMessage":"[%s] 搜索请求失败: %w","messagePattern":"\\[(.+?)\\] 搜索请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/5266ys/5266ys.go","lineNumber":182,"sourceCode":"}\n\nfunc (p *Plugin) fetchSearch(client *http.Client, keyword string) (*goquery.Document, error) {\n\tencoded, err := encodeGB18030(keyword)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 编码搜索关键词失败: %w\", p.Name(), err)\n\t}\n\tform := \"show=title%2Csmalltext&tempid=1&tbname=article&keyboard=\" + url.QueryEscape(string(encoded)) + \"&submit=\"\n\tctx, cancel := context.WithTimeout(context.Background(), requestTimeout)\n\tdefer cancel()\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, baseURL+searchPath, strings.NewReader(form))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建搜索请求失败: %w\", p.Name(), err)\n\t}\n\tsetHeaders(req, baseURL+\"/\")\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求返回 HTTP %d\", p.Name(), resp.StatusCode)\n\t}\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取搜索结果失败: %w\", p.Name(), err)\n\t}\n\tdecoded, err := decodeGB18030(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解码搜索结果失败: %w\", p.Name(), err)\n\t}\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(decoded))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果失败: %w\", p.Name(), err)\n\t}\n\treturn doc, nil","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/5266ys/5266ys.go#L164-L200","documentation":"fetchSearch wraps any error from client.Do — the actual HTTP round trip for the search POST — as '[%s] 搜索请求失败'. client.Do returns an error for DNS resolution failure, TCP connect failure, TLS errors, and, critically, when the request's context deadline (requestTimeout) expires before the response completes. All transport-level problems surface here rather than as non-200 statuses.","triggerScenarios":"client.Do(req) returns err inside fetchSearch: DNS failure for the site domain, connection refused/reset/timeout, TLS handshake failure, context deadline exceeded from context.WithTimeout(requestTimeout), or a proxy misconfiguration in the default transport.","commonSituations":"The target site is blocked or geo-restricted on the host machine; a corporate firewall/proxy drops the POST; the site is slow and requestTimeout (a few seconds) is too short; the site domain changed and DNS no longer resolves.","solutions":["Read the wrapped %w error: 'context deadline exceeded' means requestTimeout is too short or the site is slow — consider increasing requestTimeout.","Verify DNS/connectivity to the site with curl from the same host (curl -v '<baseURL>') to rule out network/DNS/firewall issues.","If a proxy is required on this machine, set HTTP(S)_PROXY or configure the http.Client's Transport with a ProxyFunc.","Check for a redirect to a new domain (site moved) and update baseURL; add a retry with backoff for transient connection resets."],"exampleFix":"// before\nresp, err := client.Do(req)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n}\n// after\nresp, err := client.Do(req)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return nil, fmt.Errorf(\"[%s] 搜索请求超时(>%s), 可尝试增大 requestTimeout: %w\", p.Name(), requestTimeout, err)\n    }\n    return nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n}","handlingStrategy":"retry","validationCode":"// 网络连通性预检(可选)\nif _, err := net.LookupHost(\"5266ys-site-domain\"); err != nil {\n    return nil, fmt.Errorf(\"DNS解析失败: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"result, err := p.Search(ctx, keyword)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        // 增大超时后重试\n    } else if isTransientNetErr(err) {\n        // 指数退避重试 2-3 次\n    } else {\n        return err\n    }\n}","preventionTips":["Set requestTimeout generously (10-30s) for slow scraping targets.","Configure proxy settings on the http.Client Transport when required by the network.","Add exponential backoff retries for transient network errors.","Check DNS/connectivity to the target site before bulk searches."],"tags":["go","http","network","timeout"],"backgroundTag":"network-request-failed","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"}