fish2018/pansou · error

入口脚本未找到搜索路由

Error message

入口脚本未找到搜索路由

What it means

Once the entry JS bundle is downloaded, the plugin locates the literal client-side search route "/s/$query" with strings.Index. If the route string is absent, it cannot derive where the search API identifier is defined and returns this error. The site's JavaScript no longer contains that route literal.

Solutions

  1. Download the asset and grep for the current search route; update the "/s/$query" literal in the plugin to the new route string.
  2. If the route moved to another chunk, adjust assetPath extraction (indexAssetPattern) or scan all script chunks until the route is found.
  3. Check whether the string is now escaped in the bundle (e.g. "\/s\/$query") and normalize assetBody before searching.
  4. Upgrade the plugin to a release matching the current site.

Example fix

// before
routeIndex := strings.Index(string(assetBody), "/s/$query")
// after
normalized := strings.ReplaceAll(string(assetBody), "\\/", "/")
routeIndex := strings.Index(normalized, "/s/$query")
Defensive patterns

Strategy: fallback

Validate before calling

assetBody, err := fetchAsset()
if err == nil && !strings.Contains(string(assetBody), "/s/$query") {
	log.Printf("route literal missing from bundle; site likely updated")
}

Type guard

func hasSearchRoute(body []byte) bool { return strings.Index(string(body), "/s/$query") >= 0 }

Try / catch

funcID, err := discoverServerFunctionID(ctx, req)
if err != nil && strings.Contains(err.Error(), "入口脚本未找到搜索路由") {
	log.Printf("xiaokupan route changed: %v", err)
	return nil, errSkipPlugin
}

Prevention

When it happens

Trigger: strings.Index(string(assetBody), "/s/$query") returns -1: the entry bundle was fetched successfully but does not contain the search route literal — the site changed routing, the wrong script was fetched, or the response is minified/encoded differently.

Common situations: Upstream framework upgrade renamed routes (e.g. "/search?q="); the fetched asset is a loader chunk rather than the route-defining chunk; a build changed string encoding (template literals, escaped slashes).

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/bc3b0c831c81cd68. Report an issue: GitHub.

Appendix: source

Thrown at plugin/xiaokupan/xiaokupan.go:253

	assetPath := string(indexAssetPattern.Find(homeBody))
	if assetPath == "" {
		return "", fmt.Errorf("首页未找到入口脚本")
	}
	assetReq, err := http.NewRequestWithContext(ctx, http.MethodGet, strings.TrimRight(p.baseURL, "/")+assetPath, nil)
	if err != nil {
		return "", err
	}
	assetReq.Header.Set("User-Agent", req.Header.Get("User-Agent"))
	assetReq.Header.Set("Referer", homeURL)
	assetBody, err := doLimitedRequest(client, assetReq, maxDiscoveryBodySize)
	if err != nil {
		return "", fmt.Errorf("读取入口脚本失败: %w", err)
	}

	routeIndex := strings.Index(string(assetBody), "/s/$query")
	if routeIndex < 0 {
		return "", fmt.Errorf("入口脚本未找到搜索路由")
	}
	windowStart := max(0, routeIndex-2048)
	hashes := hashPattern.FindAll(assetBody[windowStart:routeIndex], -1)
	if len(hashes) == 0 {
		return "", fmt.Errorf("入口脚本未找到搜索接口标识")
	}
	return string(hashes[len(hashes)-1]), nil
}

func parseSearchResponse(body []byte) ([]model.SearchResult, error) {
	var root serovalNode
	if err := stdjson.Unmarshal(body, &root); err != nil {
		return nil, fmt.Errorf("解析 Seroval 响应失败: %w", err)
	}
	decoder := newSerovalDecoder(&root)
	resultNode := decoder.objectValue(&root, "result")
	searchResultsNode := decoder.objectValue(resultNode, "searchResults")
	mergedNode := decoder.objectValue(searchResultsNode, "merged_by_type")

View on GitHub (pinned to beaa561337)