From 454710747ac37a54ab863722657a6535c0f84af9 Mon Sep 17 00:00:00 2001 From: Elivo Date: Thu, 30 Oct 2025 11:55:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20IApiMiddleware=20=E4=BB=A5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=AD=E9=97=B4=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Apewer/Web/ApiContext.cs | 12 ++++ Apewer/Web/ApiInvoker.cs | 34 +++++++++++- Apewer/Web/ApiProcessor.cs | 104 ++++++++++++++++++++++++++--------- Apewer/Web/IApiMiddleware.cs | 13 +++++ 4 files changed, 134 insertions(+), 29 deletions(-) create mode 100644 Apewer/Web/IApiMiddleware.cs diff --git a/Apewer/Web/ApiContext.cs b/Apewer/Web/ApiContext.cs index 63d1c94..9031f04 100644 --- a/Apewer/Web/ApiContext.cs +++ b/Apewer/Web/ApiContext.cs @@ -57,6 +57,18 @@ namespace Apewer.Web #endregion + #region 中间件 + + Action _middleware_callback = null; + + /// 设置中间件回调。 + internal void SetMiddlewareCallback(Action callback) => _middleware_callback = callback; + + /// 继续执行。 + public void Next() => _middleware_callback?.Invoke(this); + + #endregion + internal ApiContext(ApiInvoker invoker, ApiProvider provider, ApiEntries entries) { if (invoker == null) throw new ArgumentNullException(nameof(invoker)); diff --git a/Apewer/Web/ApiInvoker.cs b/Apewer/Web/ApiInvoker.cs index b357223..104a214 100644 --- a/Apewer/Web/ApiInvoker.cs +++ b/Apewer/Web/ApiInvoker.cs @@ -11,7 +11,7 @@ namespace Apewer.Web public sealed class ApiInvoker { - #region + #region default private static ApiInvoker _default = new ApiInvoker(); @@ -20,8 +20,7 @@ namespace Apewer.Web #endregion - object _locker = new object(); - bool _initialized = false; + #region 配置 /// 获取或设置要使用的 API 入口。 public ApiEntries Entries { get; set; } @@ -38,6 +37,29 @@ namespace Apewer.Web /// 输出前的检查。 public ApiPreOutput PreOutput { get; set; } + #endregion + + #region 中间件 + + private List _middlewares = new List(); + + /// 中间件。 + public Type[] Middlewares { get => _middlewares.ToArray(); } + + /// 添加中间件。 + public void AddMiddleware() where T : class, IApiMiddleware, new() + { + var type = typeof(T); + _middlewares.Add(type); + } + + #endregion + + #region 初始化 + + object _locker = new object(); + bool _initialized = false; + /// 执行初始化程序,每个 ApiInvoker 实例仅执行一次初始化。 public void Initialize(Action action) { @@ -50,6 +72,10 @@ namespace Apewer.Web } } + #endregion + + #region 调用 + /// 发起调用。 /// public void Invoke(ApiProvider provider) @@ -74,6 +100,8 @@ namespace Apewer.Web processor.Run(); } + #endregion + } } diff --git a/Apewer/Web/ApiProcessor.cs b/Apewer/Web/ApiProcessor.cs index 781a795..775145e 100644 --- a/Apewer/Web/ApiProcessor.cs +++ b/Apewer/Web/ApiProcessor.cs @@ -1,6 +1,8 @@ using Apewer.Network; using Apewer.Source; using System; +using System.Collections.Generic; +using System.Data; using System.Net; using System.Reflection; using static Apewer.Web.ApiUtility; @@ -50,6 +52,7 @@ namespace Apewer.Web } catch (Exception ex) { + ApiUtility.Exception(_context.Response, ex, _context.Options.WithException); var message = ex.Message(); Logger.Internals.Error(typeof(ApiInvoker), message); } @@ -141,32 +144,8 @@ namespace Apewer.Web } } - // 路由 - if (_context.Options.UseRoute) - { - var path = _context?.Request?.Url?.AbsolutePath; - path = path.TrimEnd('/'); - var action = _context.Entries.GetAction(path); - if (action != null) - { - _context.ApiAction = action; - Invoke(action); - return; - } - } - - // 反射 - if (_context.Options.UseReflection) - { - var appName = _context.Request.Application; - var application = _context.Entries.GetApplication(appName); - Invoke(application); - return; - } - - // 未匹配到 - _context.Response.Duration = Duration(_context.Beginning); - _context.Response.Model = new ApiStatusModel(404); + // 中间件 + InvokeMiddwares(); } #endregion @@ -277,6 +256,79 @@ namespace Apewer.Web #endregion + #region middleware + + Queue _mw_queue = null; + + void MiddlewareNext(ApiContext context) + { + if (_mw_queue.Count < 1) + { + Route(); + return; + } + + // 创建下一个中间件的实例 + var type = _mw_queue.Dequeue(); + var instance = Activator.CreateInstance(type); + var middleware = instance as IApiMiddleware; + if (middleware == null) throw new Exception($"类型【{type.FullName}】不是有效的中间件。"); + + // 调用 + middleware.Invoke(context); + } + + // 调用中间件。 + void InvokeMiddwares() + { + var types = _context.Invoker.Middlewares; + if (types.Length < 1) + { + Route(); + return; + } + + // 设置队列和回调。 + _mw_queue = new Queue(types); + _context.SetMiddlewareCallback(MiddlewareNext); + + // 执行。 + MiddlewareNext(_context); + } + + // 执行路由。 + void Route() + { + // 路由 + if (_context.Options.UseRoute) + { + var path = _context?.Request?.Url?.AbsolutePath; + path = path.TrimEnd('/'); + var action = _context.Entries.GetAction(path); + if (action != null) + { + _context.ApiAction = action; + Invoke(action); + return; + } + } + + // 反射 + if (_context.Options.UseReflection) + { + var appName = _context.Request.Application; + var application = _context.Entries.GetApplication(appName); + Invoke(application); + return; + } + + // 未匹配到 + _context.Response.Duration = Duration(_context.Beginning); + _context.Response.Model = new ApiStatusModel(404); + } + + #endregion + #region route // 执行 Action。 diff --git a/Apewer/Web/IApiMiddleware.cs b/Apewer/Web/IApiMiddleware.cs new file mode 100644 index 0000000..7cd5277 --- /dev/null +++ b/Apewer/Web/IApiMiddleware.cs @@ -0,0 +1,13 @@ +namespace Apewer.Web +{ + + /// 中间件。 + public interface IApiMiddleware + { + + /// 调用中间件。 + void Invoke(ApiContext context); + + } + +}