From 2e75e62bbcd27969d2490c6861cfd1e9313dfc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Mon, 10 Aug 2026 17:21:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(exception):=20=E4=BC=98=E5=8C=96=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E4=B8=AD=E9=97=B4=E4=BB=B6=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了对 Swap Trade 编辑请求的特殊处理逻辑 - 实现了针对掉期交易的诊断功能,包括 JSON 解析和验证 - 添加了专门用于检测无效利率的诊断方法 - 优化了异常日志的输出格式和内容 - 集成了缓冲区管理和流位置重置功能 - 增强了错误信息的详细程度和可读性 --- YLErpWeb/App/ExceptionMiddleware.cs | 123 +++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 4 deletions(-) diff --git a/YLErpWeb/App/ExceptionMiddleware.cs b/YLErpWeb/App/ExceptionMiddleware.cs index a0c469d2..86b10b6c 100644 --- a/YLErpWeb/App/ExceptionMiddleware.cs +++ b/YLErpWeb/App/ExceptionMiddleware.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Http; using System.Buffers; +using System.Text; +using System.Text.Json; namespace YLErp.Web.App { @@ -17,6 +19,11 @@ namespace YLErp.Web.App public async Task Invoke(HttpContext context) { + if (IsSwapTradeEditRequest(context.Request)) + { + context.Request.EnableBuffering(); + } + try { await _next.Invoke(context); @@ -41,9 +48,17 @@ namespace YLErp.Web.App if (serviceExpcetion == null || serviceExpcetion.IsFaultError) { - var result = await request.BodyReader.ReadAsync(); - var reqBody = ConvertBufferToString(result.Buffer); - LogFactory.GetLogger(context.Request.Path.Value).Error(serviceExpcetion ?? exception, $"[query]:{request.QueryString.Value};[body]:{reqBody}"); + if (IsSwapTradeEditRequest(request)) + { + var diagnostic = await GetSwapIntervalDiagnosticAsync(request); + LogFactory.GetLogger(context.Request.Path.Value).Error(serviceExpcetion ?? exception, $"[query]:{request.QueryString.Value};{diagnostic}"); + } + else + { + var result = await request.BodyReader.ReadAsync(); + var reqBody = ConvertBufferToString(result.Buffer); + LogFactory.GetLogger(context.Request.Path.Value).Error(serviceExpcetion ?? exception, $"[query]:{request.QueryString.Value};[body]:{reqBody}"); + } } } catch (Exception ex) @@ -78,6 +93,106 @@ namespace YLErp.Web.App return System.Text.Encoding.UTF8.GetString(span); } + private static bool IsSwapTradeEditRequest(HttpRequest request) + { + return string.Equals(request.Path.Value, "/swaptrade2/tradeEditJson", StringComparison.OrdinalIgnoreCase); + } + + private static async Task GetSwapIntervalDiagnosticAsync(HttpRequest request) + { + if (!request.Body.CanSeek) + { + return "[swap-interval-diagnostic]:request-body-unavailable"; + } + + request.Body.Position = 0; + using var reader = new StreamReader(request.Body, Encoding.UTF8, false, 1024, leaveOpen: true); + var requestBody = await reader.ReadToEndAsync(); + request.Body.Position = 0; + + if (string.IsNullOrWhiteSpace(requestBody)) + { + return "[swap-interval-diagnostic]:request-body-empty"; + } + + try + { + using var document = JsonDocument.Parse(requestBody); + if (!document.RootElement.TryGetProperty("swap_positions", out var positions) || positions.ValueKind != JsonValueKind.Array) + { + return "[swap-interval-diagnostic]:swap_positions-missing"; + } + + var invalidRates = new List(); + var positionIndex = 0; + foreach (var position in positions.EnumerateArray()) + { + var positionId = position.TryGetProperty("id", out var id) ? id.ToString() : "missing"; + AddInvalidRateDiagnostics(position, "SwapIntervalList", false, positionIndex, positionId, invalidRates); + AddInvalidRateDiagnostics(position, "InterestSwapInterval", true, positionIndex, positionId, invalidRates); + if (position.TryGetProperty("Obervation", out var observation)) + { + AddInvalidRateDiagnostics(observation, "Obervation.ObservationInterval", true, positionIndex, positionId, invalidRates); + } + if (invalidRates.Count >= 10) + { + break; + } + positionIndex++; + } + + return invalidRates.Count == 0 + ? "[swap-interval-diagnostic]:no-invalid-rate-in-payload" + : $"[swap-interval-diagnostic]:{string.Join(";", invalidRates)}"; + } + catch (JsonException) + { + return "[swap-interval-diagnostic]:request-json-invalid"; + } + } + + private static void AddInvalidRateDiagnostics(JsonElement position, string source, bool serializedJson, int positionIndex, string positionId, List invalidRates) + { + if (!position.TryGetProperty(source, out var intervals)) + { + return; + } + + if (serializedJson) + { + if (intervals.ValueKind != JsonValueKind.String) + { + return; + } + + try + { + using var document = JsonDocument.Parse(intervals.GetString()); + intervals = document.RootElement.Clone(); + } + catch (JsonException) + { + invalidRates.Add($"positionIndex={positionIndex},positionId={positionId},source={source},interval-json-invalid"); + return; + } + } + + if (intervals.ValueKind != JsonValueKind.Array) + { + return; + } + + var intervalIndex = 0; + foreach (var interval in intervals.EnumerateArray()) + { + if ((!interval.TryGetProperty("Rate", out var rate) || rate.ValueKind == JsonValueKind.Null) && invalidRates.Count < 10) + { + invalidRates.Add($"positionIndex={positionIndex},positionId={positionId},source={source},intervalIndex={intervalIndex},rate={(rate.ValueKind == JsonValueKind.Null ? "null" : "missing")}"); + } + intervalIndex++; + } + } + private static string GetInnerExceptionMessage(Exception ex) { var exceptionStr = ex.Message; @@ -89,4 +204,4 @@ namespace YLErp.Web.App return exceptionStr; } } -} \ No newline at end of file +}