{"record":{"id":"010dac32c02cd090","repo":"fish2018/pansou","slug":"payload-json-w","errorCode":null,"errorMessage":"解析Payload JSON失败: %w","messagePattern":"解析Payload JSON失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/susu/susu.go","lineNumber":533,"sourceCode":"\tparts := strings.Split(jwtToken, \".\")\n\tif len(parts) != 3 {\n\t\treturn \"\", fmt.Errorf(\"无效的JWT格式\")\n\t}\n\n\t// 解码Payload\n\tpayload, err := base64.RawURLEncoding.DecodeString(parts[1])\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"解码Payload失败: %w\", err)\n\t}\n\n\t// 解析JSON\n\tvar payloadData struct {\n\t\tData struct {\n\t\t\tURL string `json:\"url\"`\n\t\t} `json:\"data\"`\n\t}\n\tif err := json.Unmarshal(payload, &payloadData); err != nil {\n\t\treturn \"\", fmt.Errorf(\"解析Payload JSON失败: %w\", err)\n\t}\n\tif strings.TrimSpace(payloadData.Data.URL) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"JWT Payload中没有链接\")\n\t}\n\n\t// 缓存结果\n\tjwtDecodeCache.Store(jwtToken, payloadData.Data.URL)\n\n\treturn payloadData.Data.URL, nil\n}\n\nfunc setBrowserHeaders(req *http.Request, referer string) {\n\treq.Header.Set(\"User-Agent\", getRandomUA())\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Referer\", referer)\n}\n","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/susu/susu.go#L515-L551","documentation":"decodeJWTURL parses a JWT token, base64-decodes its payload, and unmarshals the payload JSON into a struct expecting a data.url field. This error is wrapped when json.Unmarshal fails, meaning the payload segment is not valid JSON or does not match the expected shape. It preserves the underlying decode error via %w so the root cause (syntax error, type mismatch) is visible.","triggerScenarios":"Calling getButtonDetail (or TestDecodeJWTURL) with a JWT whose payload segment decodes to bytes that are not valid JSON, or valid JSON but not an object with {\"data\":{\"url\":...}} (e.g. JSON arrays, strings, or differently-shaped claims).","commonSituations":"The site changed its JWT payload schema; the token was truncated or corrupted when copied from a button link; the payload is a different encoding (e.g. url-encoded or double-encoded) so base64 decoding yields garbage; an anti-bot page returned a placeholder token.","solutions":["Log/print the decoded payload bytes before unmarshalling to see the actual JSON shape and update the struct to match.","Verify the JWT has the standard three dot-separated segments and that the payload segment is valid base64 (handle URL-safe base64 and missing padding).","Re-fetch the token from the source page rather than reusing a cached/copied token that may be truncated.","If the upstream schema changed, adjust payloadData (e.g. url may have moved out of data) and redeploy."],"exampleFix":"// before\nvar payloadData struct {\n    Data struct {\n        URL string `json:\"url\"`\n    } `json:\"data\"`\n}\nif err := json.Unmarshal(payload, &payloadData); err != nil {\n    return \"\", fmt.Errorf(\"解析Payload JSON失败: %w\", err)\n}\n// after: tolerate both shapes\nvar payloadData struct {\n    Data struct {\n        URL string `json:\"url\"`\n    } `json:\"data\"`\n    URL string `json:\"url\"`\n}\nif err := json.Unmarshal(payload, &payloadData); err != nil {\n    return \"\", fmt.Errorf(\"解析Payload JSON失败: %w\", err)\n}\nif payloadData.Data.URL == \"\" {\n    payloadData.Data.URL = payloadData.URL\n}","handlingStrategy":"try-catch","validationCode":"parts := strings.Split(jwtToken, \".\")\nif len(parts) < 2 {\n    return fmt.Errorf(\"not a JWT: expected 3 segments, got %d\", len(parts))\n}\npayload, err := base64.RawURLEncoding.DecodeString(parts[1])\nif err != nil {\n    return fmt.Errorf(\"payload is not valid base64: %w\", err)\n}\nif !json.Valid(payload) {\n    return fmt.Errorf(\"payload is not valid JSON: %s\", payload)\n}","typeGuard":"func isValidJWTPayload(tok string) bool {\n    parts := strings.Split(tok, \".\")\n    if len(parts) != 3 {\n        return false\n    }\n    b, err := base64.RawURLEncoding.DecodeString(parts[1])\n    return err == nil && json.Valid(b)\n}","tryCatchPattern":"url, err := decodeJWTURL(jwtToken)\nif err != nil {\n    var uerr *json.SyntaxError\n    if errors.As(err, &uerr) {\n        log.Printf(\"JWT payload not JSON (syntax at offset %d), refetching token\", uerr.Offset)\n    }\n    return fallbackResolveLink(ctx, item)\n}","preventionTips":["Always decode with base64.RawURLEncoding (URL-safe, no padding) before unmarshalling.","Re-fetch tokens from the source page instead of persisting/copied token strings.","Log raw decoded payload when introducing the plugin or after site updates.","Keep a struct flexible enough (or use json.RawMessage) to absorb upstream schema drift."],"tags":["jwt","json","parsing","go"],"backgroundTag":"json-unmarshal-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"}