{"record":{"id":"23fe4800a00f6d8c","repo":"fish2018/pansou","slug":"error-23fe48","errorCode":null,"errorMessage":"字符串以转义符结尾","messagePattern":"字符串以转义符结尾","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"plugin/haitunsou/haitunsou.go","lineNumber":197,"sourceCode":"\t\tcase '\\\\':\n\t\t\tescaped = true\n\t\tcase '\\'':\n\t\t\treturn body[start:index], nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"内嵌结果字符串未闭合\")\n}\n\nfunc decodeJSSingleQuotedString(encoded []byte) ([]byte, error) {\n\tdecoded := make([]byte, 0, len(encoded))\n\tfor index := 0; index < len(encoded); index++ {\n\t\tif encoded[index] != '\\\\' {\n\t\t\tdecoded = append(decoded, encoded[index])\n\t\t\tcontinue\n\t\t}\n\t\tindex++\n\t\tif index >= len(encoded) {\n\t\t\treturn nil, fmt.Errorf(\"字符串以转义符结尾\")\n\t\t}\n\t\tswitch encoded[index] {\n\t\tcase '\\\\', '\\'', '\"', '/':\n\t\t\tdecoded = append(decoded, encoded[index])\n\t\tcase 'b':\n\t\t\tdecoded = append(decoded, '\\b')\n\t\tcase 'f':\n\t\t\tdecoded = append(decoded, '\\f')\n\t\tcase 'n':\n\t\t\tdecoded = append(decoded, '\\n')\n\t\tcase 'r':\n\t\t\tdecoded = append(decoded, '\\r')\n\t\tcase 't':\n\t\t\tdecoded = append(decoded, '\\t')\n\t\tcase 'v':\n\t\t\tdecoded = append(decoded, '\\v')\n\t\tcase '0':\n\t\t\tdecoded = append(decoded, 0)","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/haitunsou/haitunsou.go#L179-L215","documentation":"Error returned by decodeJSSingleQuotedString when the encoded string ends with a lone backslash: the escape character is the final byte with nothing following it to decode. In valid JavaScript string literals a backslash always escapes a following character, so a trailing backslash means the extracted literal is malformed — usually because the body was truncated after the marker or the scan/decode logic disagreed with the page's actual escaping.","triggerScenarios":"body ends with '\\' right at the last byte of the scanned string: page truncated mid-literal, or scanSingleQuotedString terminated at a quote that the site itself escaped differently ('\\\\'' sequences edge cases), leaving a dangling escape.","commonSituations":"Upstream emits content containing trailing backslashes (e.g. Windows-style paths in titles) that the scanner decodes differently than the browser's JS engine; truncated CDN responses.","solutions":["Inspect the decoded string's tail and the matching page source to see how the site actually escapes trailing backslashes","Make the decoder tolerant: treat a trailing lone backslash as a literal backslash instead of an error if the upstream really emits it","Retry the request in case the page was truncated","Add a round-trip unit test with a payload containing Windows paths to lock in the intended behavior"],"exampleFix":"// before\nindex++\nif index >= len(encoded) {\n    return nil, fmt.Errorf(\"字符串以转义符结尾\")\n}\n// after\nindex++\nif index >= len(encoded) {\n    decoded = append(decoded, '\\\\') // tolerate trailing literal backslash\n    return decoded, nil\n}","handlingStrategy":"try-catch","validationCode":"if len(encoded) > 0 && encoded[len(encoded)-1] == '\\\\' {\n    return errors.New(\"payload ends with dangling escape — page likely truncated\")\n}","typeGuard":"func endsWithDanglingEscape(b []byte) bool {\n    return len(b) > 0 && b[len(b)-1] == '\\\\'\n}","tryCatchPattern":"if strings.Contains(err.Error(), \"字符串以转义符结尾\") {\n    // retry the request (likely truncation) or degrade to empty results\n}","preventionTips":["Retry when this fires — usually a truncated response","Decide policy for trailing backslashes (Windows paths in titles) and encode it in tests","Keep scan and decode escape handling symmetric","Round-trip test decodeJSSingleQuotedString against real page fixtures"],"tags":["parsing","escaping","scraping"],"backgroundTag":"invalid-escape-sequence","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"}