上传源代码版本

This commit is contained in:
Im-Jenisson
2026-06-01 16:30:29 +08:00
commit b2a9b7d3c2
462 changed files with 104365 additions and 0 deletions

View File

@@ -0,0 +1,399 @@
# Caller Header 接收改造实施计划
## 概述
根据《后端Caller字段接收清单.md》的要求需要在 11 个 API 接口中从 HTTP Header 读取 `Caller` 字段(请求人姓名)。
**核心业务含义**`Caller` 记录了该次请求是由谁发起的,对于创建类接口需要**写入系统的创建人字段**,对于所有接口都需要**通过 Serilog 记录审计日志**。
**扩展性设计**:采用 Middleware 统一提取 + RequestTrackingContext 建模的方案。后续新增 `Device-Id``Request-Id` 等 Header 时,只需:
1.`RequestTrackingContext` 类中加一个属性
2. 在 Middleware 中加一行读取代码
无需修改任何 Controller。
***
## 架构设计
```
HTTP Request (Header: Caller, Device-Id, Request-Id, ...)
┌─────────────────────────┐
│ RequestTrackingMiddleware │ ← 统一提取所有追踪 Header
│ 存入 HttpContext.Items │ 写入 RequestTrackingContext
└───────────┬─────────────┘
┌─────────────────────────┐
│ Controller Action │ ← HttpContext.GetRequestTrackingContext().Caller
│ - A 类:读取 + 记录日志 │ _logger.LogInformation(...)
│ - B 类:读取 + 写创建人 │ entity.Creator = ...GetCaller();
└─────────────────────────┘
```
***
## 涉及的文件
| # | 文件 | 操作 | 说明 |
| - | -------------------------------------------------------------------- | -------- | ---------------- |
| 1 | `src/CONTROLLER/Models/RequestTrackingContext.cs` | **新建** | 追踪上下文模型 |
| 2 | `src/CONTROLLER/Middleware/RequestTrackingMiddleware.cs` | **新建** | 统一提取 Header |
| 3 | `src/CONTROLLER/Extensions/HttpContextExtensions.cs` | **新建** | HttpContext 扩展方法 |
| 4 | `src/CONTROLLER/Program.cs` | **修改** | 注册中间件 |
| 5 | `src/CONTROLLER/Controllers/LabelController.cs` | 修改 2 个方法 | 已有 Logger |
| 6 | `src/CONTROLLER/Controllers/BagTagController.cs` | 修改 4 个方法 | 需注入 Logger |
| 7 | `src/CONTROLLER/Controllers/ShippingHandoverFormController.cs` | 修改 3 个方法 | 需注入 Logger |
| 8 | `src/CONTROLLER/Controllers/ShippingHandoverFormBagTagController.cs` | 修改 1 个方法 | 需注入 Logger |
***
## 接口改造分类
### A 类:仅记录 Caller 日志7 个读操作接口)
| # | 方法 | 端点 |
| -- | --- | -------------------------------------------------------- |
| 1 | GET | `api/label/label-replace/waybill/{number}/download` |
| 2 | GET | `api/label/label-replace/waybill/{number}/downloadNoTri` |
| 3 | GET | `api/bagtag/{tagNumber}/print` |
| 4 | GET | `api/shipping-handover/{bolNumber}/print` |
| 7 | GET | `api/shipping-handover/generate-number` |
| 9 | GET | `api/bagtag/available` |
| 10 | GET | `api/shipping-handover/bag-tag/associate-by-number/{id}` |
### B 类:记录日志 + 写入系统创建人字段3 个创建/操作接口)
| # | 方法 | 端点 | 当前代码 | 改造内容 |
| - | ---- | ------------------------------ | ------------------------ | ---------------------- |
| 5 | POST | `api/bagtag/generate` | `creator` 硬编码 `"system"` | → 从 `Caller` Header 读取 |
| 6 | POST | `api/bagtag/auto-pack/start` | `request.Creator` 从请求体取 | → 用 `Caller` Header 覆盖 |
| 8 | GET | `api/shipping-handover/create` | `Creator` 从 URL 参数取 | → 用 `Caller` Header 覆盖 |
***
## 实施步骤
### 步骤 1创建 `RequestTrackingContext` 模型
`src/CONTROLLER/Models/RequestTrackingContext.cs`
```csharp
namespace CONTROLLER.Models
{
public class RequestTrackingContext
{
public string Caller { get; set; } = "system";
// 后续扩展预留:
// public string DeviceId { get; set; }
// public string RequestId { get; set; }
}
}
```
* 所有追踪 Header 的值集中在一个模型中
* 默认值 `"system"` 作为回退
* 后续新增 Header添加属性 → Middleware 中加一行读取 → 完成
***
### 步骤 2创建 `RequestTrackingMiddleware` 中间件
`src/CONTROLLER/Middleware/RequestTrackingMiddleware.cs`
```csharp
using CONTROLLER.Models;
using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Threading.Tasks;
namespace CONTROLLER.Middleware
{
public class RequestTrackingMiddleware
{
private readonly RequestDelegate _next;
public RequestTrackingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var trackingContext = new RequestTrackingContext();
var caller = context.Request.Headers["Caller"].FirstOrDefault();
if (!string.IsNullOrWhiteSpace(caller))
{
trackingContext.Caller = caller;
}
// 后续扩展只需加一行:
// var deviceId = context.Request.Headers["Device-Id"].FirstOrDefault();
// if (!string.IsNullOrWhiteSpace(deviceId)) trackingContext.DeviceId = deviceId;
context.Items["RequestTrackingContext"] = trackingContext;
await _next(context);
}
}
}
```
* 在管道最前端统一提取所有追踪 Header
* 存入 `HttpContext.Items["RequestTrackingContext"]`
* 仅在 Header 有值时才覆盖默认值(保持回退逻辑)
***
### 步骤 3创建 `HttpContextExtensions` 扩展方法
`src/CONTROLLER/Extensions/HttpContextExtensions.cs`
```csharp
using CONTROLLER.Models;
using Microsoft.AspNetCore.Http;
namespace CONTROLLER.Extensions
{
public static class HttpContextExtensions
{
public static RequestTrackingContext GetRequestTrackingContext(this HttpContext context)
{
return context.Items["RequestTrackingContext"] as RequestTrackingContext
?? new RequestTrackingContext();
}
public static string GetCaller(this HttpContext context)
{
return context.GetRequestTrackingContext().Caller;
}
}
}
```
* `GetRequestTrackingContext()` — 获取完整上下文(支持未来扩展)
* `GetCaller()` — 便捷方法,直接获取调用人
***
### 步骤 4在 `Program.cs` 中注册中间件
`app.UseResponseCompression();` 之前(或其他合适位置)添加:
```csharp
app.UseMiddleware<RequestTrackingMiddleware>();
```
需要添加 using
```csharp
using CONTROLLER.Middleware;
```
***
### 步骤 5改造 `LabelController.cs`A 类2 个接口)
已有 `ILogger<LabelController> _logger`,添加 using + 在方法入口处记录 Caller 日志:
添加 using
```csharp
using CONTROLLER.Extensions;
```
**接口 #1**`DownloadLabelByWaybillNumber`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] DownloadLabel, WaybillNumber: {WaybillNumber}", caller, waybillNumber);
```
**接口 #2**`DownloadLabelByWaybillNumberNoTrigger`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] DownloadLabelNoTrigger, WaybillNumber: {WaybillNumber}", caller, waybillNumber);
```
***
### 步骤 6改造 `BagTagController.cs`A 类 2 个 + B 类 2 个)
**前置改造**:注入 `ILogger<BagTagController>`
* 添加 `using Microsoft.Extensions.Logging;``using CONTROLLER.Extensions;`
* 添加构造函数参数和私有字段 `_logger`
**A 类 — 接口 #3** `PrintBagTag`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] PrintBagTag, TagNumber: {TagNumber}", caller, tagNumber);
```
**B 类 — 接口 #5** `GenerateBagTags`
* **当前**`var creator = /*...*/ "system";`(硬编码)
* **改为**
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] GenerateBagTags, Channel: {Channel}, Count: {Count}", caller, request.ChannelName, request.Count);
var generatedTags = await _bagTagService.GenerateBagTagsAsync(request.ChannelName, request.Count, caller);
```
**B 类 — 接口 #6** `StartAutoPack`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] StartAutoPack, TagNumber: {TagNumber}", caller, request.TagNumber);
request.Creator = caller;
var result = await _bagTagService.StartAutoPackAsync(request.TagNumber, request.Creator);
```
**A 类 — 接口 #9** `GetAvailableBagTags`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] GetAvailableBagTags, Channel: {Channel}", caller, channel);
```
***
### 步骤 7改造 `ShippingHandoverFormController.cs`A 类 2 个 + B 类 1 个)
**前置改造**:注入 `ILogger<ShippingHandoverFormController>`
* 添加 `using Microsoft.Extensions.Logging;``using CONTROLLER.Extensions;`
* 添加构造函数参数和私有字段 `_logger`
**B 类 — 接口 #8** `CreateShippingHandoverForm`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] CreateShippingHandoverForm, HandoverNumber: {Number}, Channel: {Channel}", caller, HandoverNumber, Channel);
// 用 Caller 覆盖 CreatorCaller 为空时回退为 "system"
form.Creator = caller;
```
**A 类 — 接口 #7** `GenerateShippingHandoverNumber`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] GenerateShippingHandoverNumber, Channel: {Channel}", caller, channel);
```
**A 类 — 接口 #4/#11** `PrintBillOfLading`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] PrintBillOfLading, BolNumber: {BolNumber}", caller, bolNumber);
```
***
### 步骤 8改造 `ShippingHandoverFormBagTagController.cs`A 类1 个接口)
**前置改造**:注入 `ILogger<ShippingHandoverFormBagTagController>`
* 添加 `using Microsoft.Extensions.Logging;``using CONTROLLER.Extensions;`
* 添加构造函数参数和私有字段 `_logger`
**A 类 — 接口 #10** `AssociateBagTagsByNumber`
```csharp
var caller = HttpContext.GetCaller();
_logger.LogInformation("[Caller: {Caller}] AssociateBagTagsByNumber, ShippingHandoverFormId: {Id}, TagNumbers: {Tags}", caller, shippingHandoverFormId, bagTagNumbers);
```
***
### 步骤 9验证
```bash
dotnet build src/CONTROLLER/CONTROLLER.csproj
```
***
## 未来扩展示例
假设后续要加 `Device-Id``Request-Id` 两个 Header
**只需修改 2 个文件:**
1. `RequestTrackingContext.cs` — 加 2 个属性:
```csharp
public string DeviceId { get; set; }
public string RequestId { get; set; }
```
1. `RequestTrackingMiddleware.cs` — 加 2 行:
```csharp
var deviceId = context.Request.Headers["Device-Id"].FirstOrDefault();
if (!string.IsNullOrWhiteSpace(deviceId)) trackingContext.DeviceId = deviceId;
var requestId = context.Request.Headers["Request-Id"].FirstOrDefault();
if (!string.IsNullOrWhiteSpace(requestId)) trackingContext.RequestId = requestId;
```
**Controller 中可直接使用**
```csharp
var ctx = HttpContext.GetRequestTrackingContext();
_logger.LogInformation("Caller: {C}, Device: {D}, Request: {R}", ctx.Caller, ctx.DeviceId, ctx.RequestId);
```
**无需修改任何 Controller 的业务逻辑。**
***
## B 类接口改造对照表(写入创建人字段)
| # | 方法 | 当前代码 | 改造后代码 |
| - | ---------------------------- | ------------------------- | -------------------------------------------------- |
| 5 | `GenerateBagTags` | `var creator = "system";` | `var caller = HttpContext.GetCaller();` 传入 service |
| 6 | `StartAutoPack` | `request.Creator` | `request.Creator = HttpContext.GetCaller();` |
| 8 | `CreateShippingHandoverForm` | `form.Creator = Creator;` | `form.Creator = HttpContext.GetCaller();` |
***
## A 类接口日志格式
```
[Caller: zhangsan] DownloadLabel, WaybillNumber: YW202605270001
[Caller: system] PrintBagTag, TagNumber: BT202605270001
[Caller: zhangsan] PrintBillOfLading, BolNumber: BOL202605270001
```
***
## 改造汇总
| 步骤 | 文件 | 操作 | A 类 | B 类 |
| ------ | ----------------------------------------- | -------------------- | ----- | ----- |
| 1 | `Models/RequestTrackingContext.cs` | 新建 | — | — |
| 2 | `Middleware/RequestTrackingMiddleware.cs` | 新建 | — | — |
| 3 | `Extensions/HttpContextExtensions.cs` | 新建 | — | — |
| 4 | `Program.cs` | 注册中间件 | — | — |
| 5 | `LabelController.cs` | 修改 2 个方法 | 2 | 0 |
| 6 | `BagTagController.cs` | 添加 Logger + 修改 4 个方法 | 2 | 2 |
| 7 | `ShippingHandoverFormController.cs` | 添加 Logger + 修改 3 个方法 | 2 | 1 |
| 8 | `ShippingHandoverFormBagTagController.cs` | 添加 Logger + 修改 1 个方法 | 1 | 0 |
| 9 | 构建验证 | `dotnet build` | — | — |
| **合计** | 8 个文件 | <br /> | **7** | **3** |