{"record":{"id":"3d4cb7fa173d4b7f","repo":"babalae/better-genshin-impact","slug":"serverchan-response-statuscode","errorCode":null,"errorMessage":"ServerChan调用失败，状态码: {response.StatusCode}","messagePattern":"ServerChan调用失败，状态码: (.+?)","errorType":"exception","errorClass":"NotifierException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Service/Notifier/ServerChanNotifier.cs","lineNumber":58,"sourceCode":"\n            // 生成通知标题和内容\n            string title = $\"BetterGI·更好的原神\";\n            string desp = GenerateDescription(content);\n\n            // 准备表单数据\n            var postData = $\"title={Uri.EscapeDataString(title)}&desp={Uri.EscapeDataString(desp)}\";\n\n            // 创建请求\n            var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);\n            request.Content = new StringContent(postData, Encoding.UTF8, \"application/x-www-form-urlencoded\");\n\n            // 发送请求\n            var response = await _httpClient.SendAsync(request);\n\n            // 检查响应状态\n            if (!response.IsSuccessStatusCode)\n            {\n                throw new NotifierException($\"ServerChan调用失败，状态码: {response.StatusCode}\");\n            }\n        }\n        catch (NotifierException)\n        {\n            throw;\n        }\n        catch (System.Exception ex)\n        {\n            throw new NotifierException($\"Error sending ServerChan message: {ex.Message}\");\n        }\n    }\n\n    /// <summary>\n    /// 根据sendKey格式获取正确的API URL\n    /// </summary>\n    private string GetServerChanApiUrl(string key)\n    {\n        // 判断sendkey是否以\"sctp\"开头并提取数字部分","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Service/Notifier/ServerChanNotifier.cs#L40-L76","documentation":"Thrown when the POST to the ServerChan API URL (sctapi.ftqq.com/{key}.send or {num}.push.ft07.com/send/{key}.send) returns a non-success HTTP status. The notifier only checks response.IsSuccessStatusCode and discards the body.","triggerScenarios":"HTTP 400/401 (bad/expired key), 404 (wrong key path for sctp format), 429 (frequency limit — ServerChan limits ~5 msgs/min on free tier), 5xx (service down).","commonSituations":"SendKey revoked or pasted with trailing whitespace; free-tier rate limit exceeded; ft07 endpoint number wrong; service-side maintenance.","solutions":["Read and include the response body in the exception (ServerChan returns JSON with code/message).","Verify the SendKey is current and has no whitespace.","For 429, throttle notifications (ServerChan free tier allows limited messages per minute).","For sctp keys, confirm the numeric prefix matches the ft07 account."],"exampleFix":"// before\nvar response = await _httpClient.SendAsync(request);\nif (!response.IsSuccessStatusCode)\n{\n    throw new NotifierException($\"ServerChan调用失败，状态码: {response.StatusCode}\");\n}\n\n// after\nvar response = await _httpClient.SendAsync(request);\nvar body = await response.Content.ReadAsStringAsync();\nif (!response.IsSuccessStatusCode)\n{\n    throw new NotifierException($\"ServerChan调用失败，状态码: {response.StatusCode}, 响应: {body}\");\n}","handlingStrategy":"retry","validationCode":"if (string.IsNullOrWhiteSpace(sendKey))\n    throw new InvalidOperationException(\"SendKey missing.\");\nstring apiUrl = GetServerChanApiUrl(sendKey);\nif (!Uri.TryCreate(apiUrl, UriKind.Absolute, out _))\n    throw new InvalidOperationException(\"Built ServerChan URL is invalid.\");","typeGuard":null,"tryCatchPattern":"for (int attempt = 0; ; attempt++)\ntry { await serverChanNotifier.SendAsync(data); break; }\ncatch (NotifierException ex) when (ex.Message.Contains(\"调用失败\") && attempt < 2)\n{ await Task.Delay(TimeSpan.FromSeconds(5 * (attempt + 1))); }","preventionTips":["Throttle notifications to stay under ServerChan's free-tier rate limit.","Keep the SendKey current (re-copy if revoked).","Include the response body in the error to distinguish 401/404/429."],"tags":["serverchan","http","api-failure","rate-limit","notifier"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}