From 7e13edc440e0d72c616355b487efb922b404faed Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Thu, 5 Feb 2026 23:20:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=82=E5=B8=B8=E9=80=9A?= =?UTF-8?q?=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RequestResponseLoggingMiddleware.cs | 2 + IRaCIS.Core.API/appsettings.json | 6 +- .../ProjectExceptionFilter.cs | 31 ++++++- .../Helper/OtherTool/WeComNotifier.cs | 87 +++++++++++++++++++ IRaCIS.Core.Application/TestService.cs | 6 +- 5 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 IRaCIS.Core.Application/Helper/OtherTool/WeComNotifier.cs diff --git a/IRaCIS.Core.API/_PipelineExtensions/Serilog/RequestResponseLoggingMiddleware.cs b/IRaCIS.Core.API/_PipelineExtensions/Serilog/RequestResponseLoggingMiddleware.cs index ee61eabbc..c1686fd55 100644 --- a/IRaCIS.Core.API/_PipelineExtensions/Serilog/RequestResponseLoggingMiddleware.cs +++ b/IRaCIS.Core.API/_PipelineExtensions/Serilog/RequestResponseLoggingMiddleware.cs @@ -39,6 +39,8 @@ namespace IRaCIS.Core.API._PipelineExtensions.Serilog var requestBodyPayload = await ReadRequestBody(context.Request); + context.Items["RequestBody"] = requestBodyPayload; + using (LogContext.PushProperty("RequestBody", requestBodyPayload)) { //await _next.Invoke() diff --git a/IRaCIS.Core.API/appsettings.json b/IRaCIS.Core.API/appsettings.json index 5376f4890..46d4d60fe 100644 --- a/IRaCIS.Core.API/appsettings.json +++ b/IRaCIS.Core.API/appsettings.json @@ -3,7 +3,7 @@ "SecurityKey": "ShangHaiZhanYing_SecurityKey_SHzyyl@2021", "Issuer": "Extimaging", "Audience": "EICS", - "TokenExpireMinute": "10080"//7天 + "TokenExpireMinute": "10080" //7天 }, "IpRateLimiting": { "EnableEndpointRateLimiting": true, @@ -43,6 +43,10 @@ } ] }, + "WeComNoticeConfig": { + "WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4355b98e-1e72-4678-8dfb-2fc6ad0bf449", //4355b98e-1e72-4678-8dfb-2fc6ad0bf449 //cdd97aab-d256-4f07-9145-a0a2b1555322 + "NoticeUserList": [ "ZhouHang" ] + }, "IRaCISImageStore": { "SwitchingMode": "RemainingDiskCapacity", "SwitchingRatio": 80, diff --git a/IRaCIS.Core.Application/BusinessFilter/LegacyController/ProjectExceptionFilter.cs b/IRaCIS.Core.Application/BusinessFilter/LegacyController/ProjectExceptionFilter.cs index 930c3d9cb..3231e9059 100644 --- a/IRaCIS.Core.Application/BusinessFilter/LegacyController/ProjectExceptionFilter.cs +++ b/IRaCIS.Core.Application/BusinessFilter/LegacyController/ProjectExceptionFilter.cs @@ -1,13 +1,16 @@ -using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Application.Helper.OtherTool; +using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infrastructure; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; namespace IRaCIS.Core.Application.Filter; -public class ProjectExceptionFilter(ILogger _logger, IStringLocalizer _localizer) : Attribute, IExceptionFilter +public class ProjectExceptionFilter(ILogger _logger, IStringLocalizer _localizer, IConfiguration _config, IUserInfo _userInfo) : Attribute, IExceptionFilter { public void OnException(ExceptionContext context) @@ -48,6 +51,29 @@ public class ProjectExceptionFilter(ILogger _logger, ISt context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (exception.InnerException is null ? (exception.Message) : (exception.Message + "Inner ExceptionMsg:" + exception.InnerException?.Message)), ApiResponseCodeEnum.ProgramException)); + try + { + string webhook = _config["WeComNoticeConfig:WebhookUrl"] ?? string.Empty; + var uri = new Uri(_config["SystemEmailSendConfig:SiteUrl"]); + var baseUrl = uri.GetLeftPart(UriPartial.Authority); + + var userList = _config.GetSection("WeComNoticeConfig:NoticeUserList").Get(); + + + + var requestBody = context.HttpContext.Items["RequestBody"] as string; + + + + + WeComNotifier.SendErrorAsync(webhook, baseUrl, $"{_userInfo.UserName}({_userInfo.UserTypeShortName})", context.HttpContext.Request.Path, requestBody, exception, userList).GetAwaiter().GetResult(); + } + catch (Exception ex) + { + + _logger.LogError($"异常过滤器里发送企业微信出现错误:{ex.Message}"); + } + } context.ExceptionHandled = true;//标记当前异常已经被处理过了 @@ -58,6 +84,7 @@ public class ProjectExceptionFilter(ILogger _logger, ISt _logger.LogError(errorInfo); + //_logger.LogError(exception, exception.Message); } else diff --git a/IRaCIS.Core.Application/Helper/OtherTool/WeComNotifier.cs b/IRaCIS.Core.Application/Helper/OtherTool/WeComNotifier.cs new file mode 100644 index 000000000..71395135f --- /dev/null +++ b/IRaCIS.Core.Application/Helper/OtherTool/WeComNotifier.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using RestSharp; +using System.Net; +using System.Threading.Tasks; +using IdentityModel; + +namespace IRaCIS.Core.Application.Helper.OtherTool; + + + +public static class WeComNotifier +{ + + public static async Task SendErrorAsync(string webhook, string env, string userName,string api,string json, Exception ex, params string[] atUsers) + { + try + { + var client = new RestClient(); + var request = new RestRequest(webhook, Method.Post); + + string hostName = Dns.GetHostName(); + string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + + var stack = ex.StackTrace ?? "无堆栈信息"; + stack = stack.Replace("\n", "\n> "); // 每行变成引用,防止markdown断裂 + if (stack.Length > 1000) + stack = stack.Substring(0, 1000) + "...(已截断)"; + + string atText = ""; + if (atUsers != null && atUsers.Any()) + { + foreach (var u in atUsers) + { + atText += $" <@{u}>"; // 注意空格分隔 + } + } + + + //> **运行环境:** < font color = ""comment"" >{ EnvironmentName} danger danger warning + var markdown = $@"## 🚨 系统异常告警 + > {atText} + > **部署环境:** [{env}]({env}) + > **服务器:** {hostName} + > **发生时间:** {time} + > **操作人:** {userName} + > **接口地址:** {api} + ### ❗ 异常信息 + {ex.Message} + >**📦 请求数据(JSON 格式):** +```json +{json} +``` + ### 堆栈信息(部分) + > {stack} + "; + + var payload = new + { + msgtype = "markdown", + markdown = new + { + content = markdown + } + }; + + request.AddHeader("Content-Type", "application/json"); + request.AddStringBody(JsonConvert.SerializeObject(payload), DataFormat.Json); + + var response = await client.ExecuteAsync(request); + + if (!response.IsSuccessful) + { + Log.Logger.Error($"企业微信通知失败: {response.StatusCode} {response.ErrorMessage}"); + } + } + catch (Exception notifyEx) + { + Log.Logger.Error("发送企业微信告警异常: " + notifyEx.Message); + } + } +} + diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index 5d65f40dc..591a1ec2a 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -6,6 +6,7 @@ using IRaCIS.Application.Contracts; using IRaCIS.Core.Application.BusinessFilter; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Helper.OtherTool; using IRaCIS.Core.Application.Service.BusinessFilter; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain; @@ -109,10 +110,13 @@ namespace IRaCIS.Core.Application.Service //创建一个模型验证的方法 [AllowAnonymous] - [HttpPost] + [HttpPost("{email}")] public async Task PostModelVerify(ModelVerifyCommand modelVerify) { + var webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=cdd97aab-d256-4f07-9145-a0a2b1555322"; + //await WeComNotifier.SendErrorAsync(webhook, "http://irc.test.extimaging.com/login", new Exception("测试异常"), new[] { "ZhouHang" }); + throw new Exception("手动测试异常抛出"); return ResponseOutput.Ok(modelVerify); }