{"record":{"id":"275cf5379ed019d8","repo":"fish2018/pansou","slug":"error-275cf5","errorCode":null,"errorMessage":"入口脚本未找到搜索接口标识","messagePattern":"入口脚本未找到搜索接口标识","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/xiaokupan/xiaokupan.go","lineNumber":258,"sourceCode":"\tassetReq, err := http.NewRequestWithContext(ctx, http.MethodGet, strings.TrimRight(p.baseURL, \"/\")+assetPath, nil)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tassetReq.Header.Set(\"User-Agent\", req.Header.Get(\"User-Agent\"))\n\tassetReq.Header.Set(\"Referer\", homeURL)\n\tassetBody, err := doLimitedRequest(client, assetReq, maxDiscoveryBodySize)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"读取入口脚本失败: %w\", err)\n\t}\n\n\trouteIndex := strings.Index(string(assetBody), \"/s/$query\")\n\tif routeIndex < 0 {\n\t\treturn \"\", fmt.Errorf(\"入口脚本未找到搜索路由\")\n\t}\n\twindowStart := max(0, routeIndex-2048)\n\thashes := hashPattern.FindAll(assetBody[windowStart:routeIndex], -1)\n\tif len(hashes) == 0 {\n\t\treturn \"\", fmt.Errorf(\"入口脚本未找到搜索接口标识\")\n\t}\n\treturn string(hashes[len(hashes)-1]), nil\n}\n\nfunc parseSearchResponse(body []byte) ([]model.SearchResult, error) {\n\tvar root serovalNode\n\tif err := stdjson.Unmarshal(body, &root); err != nil {\n\t\treturn nil, fmt.Errorf(\"解析 Seroval 响应失败: %w\", err)\n\t}\n\tdecoder := newSerovalDecoder(&root)\n\tresultNode := decoder.objectValue(&root, \"result\")\n\tsearchResultsNode := decoder.objectValue(resultNode, \"searchResults\")\n\tmergedNode := decoder.objectValue(searchResultsNode, \"merged_by_type\")\n\tmergedNode = decoder.resolve(mergedNode)\n\tif mergedNode == nil || mergedNode.Props == nil {\n\t\treturn nil, fmt.Errorf(\"响应缺少 merged_by_type\")\n\t}\n","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/xiaokupan/xiaokupan.go#L240-L276","documentation":"After locating the search route in the entry bundle, the plugin looks backwards up to 2048 bytes for hash-like identifiers (hashPattern) that encode the server function ID. If none are found it returns this error, because the server function ID needed to call the search API could not be extracted.","triggerScenarios":"hashPattern.FindAll over the 2048-byte window before \"/s/$query\" yields zero matches: the bundle layout changed so the hash is farther away, in a different format, or generated at runtime.","commonSituations":"Bundler upgrade changed chunk hashing/format or moved the function ID reference beyond the 2048-byte window; the ID is now fetched from a separate manifest file; minification altered identifier shape.","solutions":["Inspect the bundle around the route string and update hashPattern to the new identifier format.","Widen the 2048-byte window (or search the whole bundle) if the hash is simply farther from the route literal.","If the ID moved to a manifest/build-metadata file, fetch and parse that file instead.","Upgrade the plugin to a version compatible with the current site build."],"exampleFix":"// before\nwindowStart := max(0, routeIndex-2048)\nhashes := hashPattern.FindAll(assetBody[windowStart:routeIndex], -1)\n// after\nwindowStart := max(0, routeIndex-16384)\nhashes := hashPattern.FindAll(assetBody[windowStart:routeIndex], -1)","handlingStrategy":"validation","validationCode":"window := assetBody[max(0, routeIndex-16384):routeIndex]\nif len(hashPattern.FindAll(window, -1)) == 0 {\n\tlog.Printf(\"no function-ID hash near route; pattern needs update\")\n}","typeGuard":"func hasFunctionIDHash(body []byte, routeIndex int) bool {\n\twindow := body[max(0, routeIndex-2048):routeIndex]\n\treturn len(hashPattern.FindAll(window, -1)) > 0\n}","tryCatchPattern":"funcID, err := discoverServerFunctionID(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"入口脚本未找到搜索接口标识\") {\n\tlog.Printf(\"hash pattern outdated: %v\", err)\n\treturn nil, errSkipPlugin\n}","preventionTips":["Widen the lookahead window defensively rather than assuming the hash sits within 2KB.","Re-verify hashPattern against a freshly downloaded bundle whenever the site ships a new build.","Cache the discovered function ID with a TTL and refresh silently on failure."],"tags":["scraping","regex","javascript","upstream-change"],"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"}