Files

84 lines
3.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Security.Authentication;
using System.Text;
namespace Common.Notify
{
/// <summary>
/// 通知推送异常诊断工具
/// HttpClient 网络异常(尤其 SSL/TLS 握手失败)的真实根因藏在 InnerException 链里,
/// 只记录外层 ex.Message 会得到"see inner exception"这类无用信息。
/// 本工具展开整条异常链并针对常见网络故障给出可读排查提示,供三个 Notifier 复用。
/// </summary>
public static class NotifyError
{
/// <summary>
/// 将异常展开为"外层 -> 内层 -> ..."的可读描述,并附加常见网络故障排查提示
/// </summary>
public static string Describe(Exception? ex)
{
if (ex == null) return "未知错误";
var sb = new StringBuilder();
var current = ex;
int depth = 0;
// 最多展开 5 层,防止极端嵌套导致信息过长
while (current != null && depth < 5)
{
if (depth > 0) sb.Append(" -> ");
sb.Append(current.Message);
current = current.InnerException;
depth++;
}
if (IsTimeout(ex))
{
sb.Append("|排查:请求超时,请确认目标地址可达、Webhook 域名解析正常、无防火墙拦截出站 443");
}
else if (IsSslFailure(ex))
{
sb.Append("|排查:SSL/TLS 握手失败,常见原因为 " +
"①服务器无法访问外网(工控内网请改用\"跨网中转(Outbox)\"推送模式,由跳板机 AlertBridge 实际发送) " +
"②企业代理/防火墙做 SSL 拦截且其根证书未被本机信任 " +
"③系统时间不准导致证书校验失败 " +
"④Webhook 地址主机名或端口有误(非标准 HTTPS 端口)");
}
return sb.ToString();
}
/// <summary>
/// 是否为超时(TaskCanceledException 且非用户主动取消,或 TimeoutException
/// </summary>
private static bool IsTimeout(Exception ex)
{
for (var c = ex; c != null; c = c.InnerException)
{
if (c is TimeoutException) return true;
// HttpClient 超时表现为 TaskCanceledException,内部通常带 TimeoutException
if (c is TaskCanceledException && c.InnerException is TimeoutException) return true;
}
return false;
}
/// <summary>
/// 是否为 SSL/TLS 握手或证书校验失败
/// </summary>
private static bool IsSslFailure(Exception ex)
{
for (var c = ex; c != null; c = c.InnerException)
{
if (c is AuthenticationException) return true;
var msg = c.Message;
if (!string.IsNullOrEmpty(msg) &&
(msg.Contains("SSL", StringComparison.OrdinalIgnoreCase) ||
msg.Contains("TLS", StringComparison.OrdinalIgnoreCase) ||
msg.Contains("certificate", StringComparison.OrdinalIgnoreCase)))
{
return true;
}
}
return false;
}
}
}