如何限制DataSnap WebBroker应用中同一来源的重复请求?
拦截DataSnap WebBroker中同一来源重复请求并解决冻结问题
一、重复请求拦截实现(适配Delphi 10.3)
针对同一来源的重复请求,可在WebBroker请求入口做拦截,核心是维护线程安全的请求状态池,标记正在处理的请求:
1. 生成请求唯一标识
用客户端IP、请求路径、请求内容(GET参数/POST Body)组合生成唯一ID,避免误判:function GetRequestUniqueID(Request: TWebRequest): string; var ContentStr: string; begin ContentStr := ''; if Request.MethodType = mtPOST then ContentStr := Request.Content else ContentStr := Request.QueryFields.Text; // 用哈希缩短字符串,避免过长 Result := Request.RemoteAddr + '|' + Request.PathInfo + '|' + THashSHA2.GetHashString(ContentStr); end;2. 初始化线程安全的请求状态容器
在WebModule的创建/销毁事件中维护状态池,用临界区保证线程安全:var ProcessingReqs: TDictionary<string, Boolean>; ReqCS: TCriticalSection; procedure TWebModule1.WebModuleCreate(Sender: TObject); begin ReqCS := TCriticalSection.Create; ProcessingReqs := TDictionary<string, Boolean>.Create; end; procedure TWebModule1.WebModuleDestroy(Sender: TObject); begin ProcessingReqs.Free; ReqCS.Free; end;3. 请求前置拦截逻辑
在WebModule的OnActionExecute事件中加入拦截,检测到重复请求直接返回提示:procedure TWebModule1.WebModuleActionExecute(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); var ReqID: string; IsProcessing: Boolean; begin ReqID := GetRequestUniqueID(Request); ReqCS.Enter; try IsProcessing := ProcessingReqs.TryGetValue(ReqID, IsProcessing) and IsProcessing; if IsProcessing then begin Response.StatusCode := 429; Response.Content := '重复请求,请稍后再试'; Handled := True; Exit; end; ProcessingReqs.AddOrSetValue(ReqID, True); finally ReqCS.Leave; end; // --- 正常处理请求的逻辑放在这里 --- // 请求完成后移除标记 ReqCS.Enter; try ProcessingReqs.Remove(ReqID); finally ReqCS.Leave; end; end;
二、解决频繁请求导致的冻结与CPU错误
应用冻结和CPU问题多源于线程冲突、资源泄漏或线程池配置不合理:
- 保证共享资源线程安全
DataSnap WebBroker默认多线程处理请求,数据库连接、全局变量等共享资源必须用临界区或线程安全容器保护,避免多线程竞争。 - 异步处理耗时操作
若请求包含大查询、文件IO等耗时逻辑,不要在请求线程同步执行,改用TTask或TThread异步处理,完成后再返回响应,避免阻塞线程池。 - 调整线程池大小
在WebModule属性中找到ThreadPoolSize,根据服务器CPU核心数设置合理值(比如4核CPU设为8-12),避免线程过多导致CPU耗尽。 - 排查内存泄漏
开启Delphi自带的FastMM内存泄漏检测,检查请求处理过程中未释放的对象,频繁泄漏会导致性能下降甚至冻结。
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

