{"record":{"id":"b64ed20c4f4b15b5","repo":"fish2018/pansou","slug":"error-b64ed2","errorCode":null,"errorMessage":"站点地址不能包含参数或锚点","messagePattern":"站点地址不能包含参数或锚点","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/gying/gying.go","lineNumber":615,"sourceCode":"\tif baseURL == \"\" {\n\t\treturn \"\", fmt.Errorf(\"站点地址不能为空\")\n\t}\n\tif !strings.HasPrefix(baseURL, \"http://\") && !strings.HasPrefix(baseURL, \"https://\") {\n\t\tbaseURL = \"https://\" + baseURL\n\t}\n\n\tparsed, err := url.Parse(baseURL)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"站点地址格式错误: %v\", err)\n\t}\n\tif parsed.Scheme != \"http\" && parsed.Scheme != \"https\" {\n\t\treturn \"\", fmt.Errorf(\"站点地址必须以 http:// 或 https:// 开头\")\n\t}\n\tif parsed.Host == \"\" {\n\t\treturn \"\", fmt.Errorf(\"站点地址缺少域名\")\n\t}\n\tif parsed.RawQuery != \"\" || parsed.Fragment != \"\" {\n\t\treturn \"\", fmt.Errorf(\"站点地址不能包含参数或锚点\")\n\t}\n\tif parsed.Path != \"\" && parsed.Path != \"/\" {\n\t\treturn \"\", fmt.Errorf(\"站点地址不能包含路径\")\n\t}\n\n\t// HTTP clients do not consistently convert Unicode hostnames to IDNA.\n\t// Store the ASCII form so both the config page and requests are reliable.\n\thostname, err := idna.Lookup.ToASCII(parsed.Hostname())\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"站点域名格式错误: %v\", err)\n\t}\n\thost := hostname\n\tif port := parsed.Port(); port != \"\" {\n\t\thost += \":\" + port\n\t}\n\treturn parsed.Scheme + \"://\" + host, nil\n}\n","sourceCodeStart":597,"sourceCodeEnd":633,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/gying/gying.go#L597-L633","documentation":"This error comes from the gying plugin's base-URL validation (normalizeSiteURL around plugin/gying.go:615). It fires when the configured site address, after url.Parse, still carries a query string (?...) or a fragment (#...). The plugin expects a bare origin like https://example.com because requests are built internally by appending fixed API paths.","triggerScenarios":"Calling the plugin's config/set-URL path with a value such as https://example.com/?src=app or https://example.com/#top; pasting a URL copied from a browser address bar that includes tracking query params or an anchor.","commonSituations":"Users paste a full page URL (with search params or section anchors) into the plugin's site-address config field instead of the site origin.","solutions":["Remove the query string and fragment, keeping only scheme://host (e.g. https://example.com).","If the URL came from a browser, copy the origin up to and including the TLD, dropping everything after '?' or '#'.","Re-save the plugin config and restart/reload the plugin."],"exampleFix":"// before\np.saveConfig(\"https://example.com/?utm_source=bar#main\")\n// after\np.saveConfig(\"https://example.com\")","handlingStrategy":"validation","validationCode":"u, err := url.Parse(siteURL)\nif err != nil || u.Host == \"\" { return fmt.Errorf(\"invalid site URL\") }\nif u.RawQuery != \"\" || u.Fragment != \"\" || (u.Path != \"\" && u.Path != \"/\") { return fmt.Errorf(\"site URL must be a bare origin\") }","typeGuard":"func isBareOrigin(raw string) bool {\n\tu, err := url.Parse(raw)\n\treturn err == nil && u.Host != \"\" && u.RawQuery == \"\" && u.Fragment == \"\" && (u.Path == \"\" || u.Path == \"/\")\n}","tryCatchPattern":"baseURL, err := normalizeSiteURL(input)\nif err != nil {\n\tlog.Printf(\"invalid site URL %q: %v\", input, err)\n\treturn err\n}","preventionTips":["Copy only the origin (scheme://host) from the browser, not the full page URL.","Strip query and fragment in your UI before saving the config.","Add a client-side URL field validator rejecting '?', '#', and path suffixes."],"tags":["config","url","validation"],"backgroundTag":"invalid-url","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"}