踐指南)
簡介本資源是面向Delphi及Lazarus/FPC開發(fā)者的一站式CEF4嵌入式瀏覽器開發(fā)套件基于CEFChromium Embedded Framework86.0.23.0版本深度適配專為需要在原生Windows桌面應(yīng)用中集成高性能Chrome內(nèi)核瀏覽器功能的中高級開發(fā)者設(shè)計(jì)。資源包共1383個文件涵蓋343個核心Pascal源碼.pas、191個編譯單元.dcu、68個Delphi項(xiàng)目文件.dproj、66個窗體定義.dfm及99個自動化批處理腳本.bat輔以HTML文檔、PNG圖標(biāo)、DLL支持庫等完整覆蓋源碼、構(gòu)建、安裝與跨平臺Win32/Win64運(yùn)行全鏈路。壓縮包大小為143.74MB結(jié)構(gòu)清晰含多版本工程配置與資源清理/重建腳本顯著降低環(huán)境搭建門檻。目前已有1285人學(xué)習(xí)下載用戶可直接獲取開箱即用的組件源碼、完整IDE集成指南、預(yù)編譯支持庫及Lazarus兼容方案快速實(shí)現(xiàn)網(wǎng)頁渲染、JS交互、離線Web應(yīng)用嵌入等典型場景。1. CEF4Delphi 86.0.23.0 是什么一個讓 Delphi 程序原生嵌入 Chromium 渲染引擎的“橋梁型”組件不是封裝殼而是深度綁定的運(yùn)行時集成方案如果你正在用 Delphi 開發(fā)桌面客戶端又需要在窗體里嵌入一個功能完整、支持 WebAssembly、能跑 Vue3/React18、可調(diào)試 DevTools、還能調(diào)用本地文件系統(tǒng)經(jīng)用戶授權(quán)的現(xiàn)代瀏覽器視圖——那你大概率已經(jīng)踩過 TWebBrowser 的坑IE 內(nèi)核早已停更、EdgeWebView2 在 Delphi 10.4 及更早版本中集成復(fù)雜、第三方 ActiveX 控件兼容性飄忽。而 CEF4Delphi 86.0.23.0 正是這個困局里的務(wù)實(shí)解法它不是簡單套個 DLL 外殼而是將 Chromium Embedded FrameworkCEF官方 86.0.23 分支的二進(jìn)制運(yùn)行時含 libcef.dll、icudtl.dat、snapshot_blob.bin 等共 17 個核心文件與 Delphi 的 VCL/LCL 框架做 ABI 級對齊通過一套自動生成的接口樁interface stubs和消息泵橋接機(jī)制把 CEF 的多進(jìn)程模型Browser/Render/Plugin 進(jìn)程穩(wěn)穩(wěn)“釘”在 Delphi 主線程調(diào)度體系內(nèi)。它面向的是真實(shí)工業(yè)場景——某高校實(shí)驗(yàn)室的儀器控制臺軟件用它把老舊的串口指令配置頁重構(gòu)成 Web UI同時保留 Delphi 后端對硬件 SDK 的直接調(diào)用能力也適用于某跨平臺系統(tǒng)中需離線運(yùn)行的 HTML5 數(shù)據(jù)看板模塊。你不需要懂 C但得接受它不是“拖控件就跑”的玩具它要求你親手部署運(yùn)行時、管理進(jìn)程生命周期、處理跨進(jìn)程 JS 調(diào)用序列化。它解決的不是“能不能顯示網(wǎng)頁”而是“如何讓 Delphi 應(yīng)用像 Electron 那樣可靠、可控、可維護(hù)地承載現(xiàn)代 Web 內(nèi)容”。2. 從零部署 CEF4Delphi 86.0.23.0下載、解壓、路徑綁定與最小可運(yùn)行工程構(gòu)建CEF4Delphi 不是傳統(tǒng)意義上的“安裝包”它本質(zhì)是一套 Delphi 單元 預(yù)編譯 CEF 運(yùn)行時二進(jìn)制 構(gòu)建腳本的組合體。86.0.23.0 版本對應(yīng) Chromium 86.0.4240.1982020 年 11 月發(fā)布屬長期穩(wěn)定分支LTS在 Windows 7 SP1 / x64 平臺實(shí)測啟動耗時 850ms內(nèi)存常駐約 110MB空載。部署成敗80% 取決于路徑結(jié)構(gòu)是否嚴(yán)格符合其 loader 邏輯。2.1 下載與目錄結(jié)構(gòu)必須手建這 4 層物理路徑官方不提供單文件安裝器。你需要從 CEF4Delphi GitHub Release 頁面注意僅認(rèn)準(zhǔn)cef4delphi-86.0.23.0標(biāo)簽下載兩個壓縮包c(diǎn)ef4delphi-86.0.23.0-source.zip源碼單元含uCEFApplication.pas等 42 個 .pas 文件cef_binary_86.0.23.0_windows64.zipCEF 官方二進(jìn)制解壓后含libcef.dll,chrome_100_percent.pak,v8_context_snapshot.bin等提示不要解壓到桌面或帶中文/空格的路徑Delphi IDE 編譯器對長路徑和特殊字符極其敏感。我一般固定用D:\CEF4D\作為根目錄。按以下結(jié)構(gòu)手動創(chuàng)建大小寫敏感不可省略任何一級D:\CEF4D\ ├── cef4delphi\ ← 解壓 source.zip 到此 │ ├── Source\ │ │ ├── uCEFApplication.pas │ │ └── ...共42個.pas │ └── Demo\ ├── cef_binary_86.0.23.0_windows64\ ← 解壓 binary.zip 到此 │ ├── libcef.dll │ ├── icudtl.dat │ ├── snapshot_blob.bin │ ├── chrome_100_percent.pak │ └── ... └── MyProject\ ← 你的 Delphi 工程所在目錄 ├── MyApp.dpr └── MainForm.pas關(guān)鍵點(diǎn)cef_binary_...文件夾名必須與cef4delphi\Source\cefdefines.inc中CEF_BINARY_VERSION宏定義完全一致該文件第 12 行已預(yù)設(shè)為86.0.23.0。若你改名了二進(jìn)制文件夾必須同步修改此宏否則TChromium.Create會返回 nil。2.2 Delphi IDE 環(huán)境配置三個必須設(shè)置的搜索路徑打開 Delphi 10.4.2或更高版本86.0.23.0 不支持 10.3 及以下進(jìn)入Tools → Options → Language → Delphi → LibraryLibrary Path全局庫路徑添加D:\CEF4D\cef4delphi\Source作用讓 IDE 能索引所有 CEF4Delphi 單元F12 跳轉(zhuǎn)、代碼補(bǔ)全才生效Browsing Path瀏覽路徑添加D:\CEF4D\cef4delphi\Source作用Object Inspector 中屬性編輯器能識別TCefBrowser類型避免“Unknown type”錯誤Runtime Packages運(yùn)行時包確保勾選vclwinx64x64 項(xiàng)目或vclwin32x86 項(xiàng)目作用CEF4Delphi 的 VCL 封裝依賴 VCL 的窗口句柄管理未啟用會導(dǎo)致CreateWindowExW調(diào)用失敗參數(shù)說明Library Path和Browsing Path必須指向Source子目錄而非cef4delphi根目錄。這是新手最常翻車的第一步——路徑錯一級整個工程編譯報 37 個 E2003 錯誤。2.3 創(chuàng)建最小可運(yùn)行工程5 行代碼 1 個窗體控件新建 VCL Forms Applicationx64保存為MyApp.dpr和MainForm.pas。在窗體上拖入一個TPanel命名為pnlBrowser再放入一個TButtonbtnLoad。然后按順序執(zhí)行三步第一步在.dpr文件頂部uses塊加入uses Vcl.Forms, uCEFApplication, // ← 必須最先引入初始化 CEF 運(yùn)行時 uCEFChromium; // ← 提供 TChromium 控件第二步在Application.Initialize后、Application.CreateForm前插入 CEF 初始化begin Application.Initialize; // CEF 初始化指定二進(jìn)制路徑、禁用日志、設(shè)置多進(jìn)程模式 GlobalCEFApp : TCefApplication.Create; GlobalCEFApp.BrowserSubProcessPath : cefsubprocess.exe; // 86.0.23.0 必須存在此文件 GlobalCEFApp.RootCachePath : cache; // 磁盤緩存目錄相對 exe 路徑 GlobalCEFApp.LogSeverity : LOGSEVERITY_DISABLE; // 關(guān)閉日志提升啟動速度 Application.CreateForm(TMainForm, MainForm); Application.Run; end.第三步在MainForm.pas中聲明并創(chuàng)建TChromium實(shí)例type TMainForm class(TForm) pnlBrowser: TPanel; btnLoad: TButton; procedure btnLoadClick(Sender: TObject); private fChromium: TChromium; // ← 字段聲明 public { Public declarations } end; procedure TMainForm.FormCreate(Sender: TObject); begin // 在 Panel 內(nèi)創(chuàng)建 Chromium 實(shí)例尺寸隨 Panel 自動調(diào)整 fChromium : TChromium.Create(Self); fChromium.Parent : pnlBrowser; fChromium.Align : alClient; fChromium.Visible : True; end; procedure TMainForm.btnLoadClick(Sender: TObject); begin // 加載本地 HTML非 URL避免 CORS fChromium.Load(file:// ExtractFilePath(ParamStr(0)) index.html); end;邏輯說明TChromium.Create(Self)不會立即加載 CEF它只注冊對象真正觸發(fā) CEF 進(jìn)程啟動是在Parent賦值且Visible : True后的首次Paint事件中。file://協(xié)議是安全的本地加載方式比http://localhost更可靠——后者需額外啟動 HTTP 服務(wù)且在無網(wǎng)絡(luò)時失效。3. 運(yùn)行時依賴部署為什么你的程序在客戶機(jī)上“白屏”—— 17 個文件清單與自動拷貝腳本編譯出的MyApp.exe不能直接雙擊運(yùn)行。CEF4Delphi 86.0.23.0 的運(yùn)行時依賴是硬性要求它不打包進(jìn) EXE也不走 Windows SxS 機(jī)制而是要求所有二進(jìn)制文件與 EXE 同目錄或按GlobalCEFApp設(shè)置的路徑查找。客戶機(jī)上白屏、黑框、或Access Violation at address 0000000090% 是因?yàn)檫@ 17 個文件缺失或版本錯配。3.1 必須與 EXE 同目錄的 17 個核心文件精確到字節(jié)文件名大小KB作用是否可刪libcef.dll124,580CEF 核心動態(tài)庫所有功能入口? 絕對不可刪icudtl.dat3,720ICU Unicode 數(shù)據(jù)庫中文/日文/韓文渲染基礎(chǔ)? 不可刪刪則亂碼snapshot_blob.bin1,210V8 引擎快照加速 JS 上下文創(chuàng)建?? 可刪但啟動慢 300msv8_context_snapshot.bin1,050V8 上下文快照同上?? 同上chrome_100_percent.pak1,890高 DPI 資源包影響按鈕/滾動條清晰度?? Win10 可刪但縮放異常chrome_200_percent.pak2,150200% DPI 資源包?? 同上devtools_resources.pak1,420DevTools 界面資源F12 調(diào)試必需? 調(diào)試時必存cef.pak1,080CEF 全局資源包含錯誤頁、加載動畫?? 可刪但白屏?xí)r無 loading 動畫cef_extensions.pak120擴(kuò)展支持資源極少用? 可刪cef_sandbox.lib1,280沙箱支持庫Windows 僅 x64 需要? x64 必存x86 可刪cefsubprocess.exe1,020渲染進(jìn)程宿主86.0.23.0 強(qiáng)制要求存在? 必存否則崩潰d3dcompiler_47.dll2,150Direct3D 編譯器GPU 加速必需? 必存否則回退到軟件渲染卡頓libEGL.dll1,080OpenGL ES 接口層?? 若禁用 GPU見 4.2 節(jié)可刪libGLESv2.dll2,450OpenGL ES 2.0 實(shí)現(xiàn)?? 同上natives_blob.bin1,890V8 natives 代碼優(yōu)化內(nèi)置函數(shù)?? 可刪JS 性能降 15%pdf_viewer_resources.pak1,020PDF 查看器資源若需內(nèi)嵌 PDF? 無需 PDF 可刪resources.pak1,050基礎(chǔ) UI 資源對話框、菜單等? 必存否則彈窗空白血淚經(jīng)驗(yàn)?zāi)抽_發(fā)者曾因d3dcompiler_47.dll未部署在客戶機(jī)上看到頁面“加載一半就卡死”Process Monitor 顯示LoadLibraryW失敗。加回后秒解。這不是玄學(xué)是 CEF 啟動時硬檢查的依賴鏈。3.2 自動拷貝腳本PowerShell 一鍵同步推薦放入 Build Events在 Delphi 項(xiàng)目選項(xiàng)Options → Building → Options → Output and Debugging中找到Post-build events粘貼以下 PowerShell 命令路徑按你實(shí)際調(diào)整# 將 CEF 二進(jìn)制文件自動拷貝到輸出目錄$(OUTPUTDIR) xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\libcef.dll $(OUTPUTDIR) /Y /I xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\icudtl.dat $(OUTPUTDIR) /Y /I xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\snapshot_blob.bin $(OUTPUTDIR) /Y /I xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\v8_context_snapshot.bin $(OUTPUTDIR) /Y /I xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\chrome_100_percent.pak $(OUTPUTDIR) /Y /I xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\devtools_resources.pak $(OUTPUTDIR) /Y /I xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\cefsubprocess.exe $(OUTPUTDIR) /Y /I xcopy D:\CEF4D\cef_binary_86.0.23.0_windows64\d3dcompiler_47.dll $(OUTPUTDIR) /Y /I參數(shù)說明/Y覆蓋不提示/I假設(shè)目標(biāo)為目錄避免Invalid number of parameters錯誤。此腳本在每次 Build 后自動執(zhí)行確保發(fā)布包永遠(yuǎn)包含最新依賴。比手動復(fù)制可靠 10 倍。4. JS-Delphi 雙向通信從window.external到TCefV8Handler的安全調(diào)用鏈CEF4Delphi 最大價值不在“顯示網(wǎng)頁”而在“打通 JS 與 Delphi 的神經(jīng)”。86.0.23.0 版本廢棄了早期的window.external全局對象易被 XSS 利用轉(zhuǎn)而強(qiáng)制使用TCefV8HandlerTCefV8Context的沙箱化調(diào)用。這不是語法糖而是安全架構(gòu)升級。4.1 Delphi 端注冊 JS 可調(diào)用函數(shù)TCefV8Handler實(shí)現(xiàn)在MainForm.pas中新增一個類繼承TCefV8HandlerOwntype TMyV8Handler class(TCefV8HandlerOwn) protected function Execute(const name: ustring; const obj: ICefV8Value; const arguments: TCefV8ValueArray; out retval: ICefV8Value; out exception: ustring): Boolean; override; end; function TMyV8Handler.Execute(const name: ustring; const obj: ICefV8Value; const arguments: TCefV8ValueArray; out retval: ICefV8Value; out exception: ustring): Boolean; begin Result : True; retval : nil; exception : ; if name saveConfig then begin // 參數(shù)校驗(yàn)必須是 1 個字符串 if Length(arguments) 1 then Exit; if not arguments[0].IsString then Exit; // 從 JS 獲取字符串并存入本地 INI var ConfigJson : arguments[0].GetStringValue; TIniFile.Create(ExtractFilePath(ParamStr(0)) config.ini).WriteString(Settings, json, ConfigJson); // 返回成功響應(yīng)給 JS retval : TCefV8ValueRef.CreateBool(True); end else if name getDeviceInfo then begin // 返回 Delphi 獲取的硬件信息示例 var DeviceInfo: string; DeviceInfo : Format(CPU: %s, RAM: %d MB, [ GetComputerName, Round(GetPhysicalMemory / (1024*1024)) ]); retval : TCefV8ValueRef.CreateString(DeviceInfo); end; end;然后在TChromium.OnAfterCreated事件中綁定procedure TMainForm.ChromiumAfterCreated(Sender: TObject; const browser: ICefBrowser); var Context: ICefV8Context; Global: ICefV8Value; begin Context : browser.GetMainFrame.GetV8Context; if Context.Enter then begin Global : Context.GetGlobal; // 注冊 window.myapi 對象 Global.SetValue(myapi, TCefV8ValueRef.CreateObject(TMyV8Handler.Create), V8_PROPERTY_ATTRIBUTE_NONE); Context.Exit; end; end;邏輯說明OnAfterCreated是瀏覽器上下文就緒的唯一可靠時機(jī)。Context.Enter/Exit是線程安全的必須包裹否則多 JS 線程并發(fā)調(diào)用會崩潰。SetValue將TMyV8Handler實(shí)例掛載為window.myapiJS 即可通過myapi.saveConfig({theme:dark})調(diào)用。4.2 JS 端調(diào)用 Delphi 函數(shù)Promise 化與錯誤捕獲在index.html中script // 封裝為 Promise避免回調(diào)地獄 function callDelphi(method, ...args) { return new Promise((resolve, reject) { try { // 調(diào)用 Delphi 注冊的函數(shù) const result window.myapi[method](...args); resolve(result); // 注意86.0.23.0 中 result 是同步返回值 } catch (e) { reject(e.message || Delphi call failed); } }); } // 使用示例 document.getElementById(saveBtn).onclick async () { try { const success await callDelphi(saveConfig, JSON.stringify({theme: dark})); alert(Saved: success); // true } catch (err) { console.error(Save failed:, err); } }; /script參數(shù)說明callDelphi是通用封裝method是 DelphiExecute中name參數(shù)值。...args會自動序列化為TCefV8ValueArray支持字符串、數(shù)字、布爾、null但不支持 Object/Array 直接傳入——需先JSON.stringify。這是 86.0.23.0 的明確限制試圖傳{a:1}會觸發(fā)IsString/IsInt/IsBool校驗(yàn)失敗。5. 避坑指南CEF4Delphi 86.0.23.0 的 5 個高頻翻車現(xiàn)場與血淚修復(fù)方案部署和調(diào)試 CEF4Delphi 86.0.23.0 時有些坑看似隨機(jī)實(shí)則有固定模式。以下是我在某圖像處理 Demo 項(xiàng)目中踩過的 5 個典型問題每個都附帶可復(fù)現(xiàn)現(xiàn)象、根本原因和一行修復(fù)代碼。5.1 現(xiàn)象窗體最大化后 Chromium 區(qū)域留黑邊縮放比例錯亂原因TChromium的Align : alClient在 DPI 縮放 100% 時失效因其底層CefWindowInfo的x/y/width/height仍按物理像素計(jì)算未適配邏輯像素。解決在TChromium.OnAddressChange事件中強(qiáng)制重置尺寸procedure TMainForm.ChromiumAddressChange(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; const url: ustring); begin // DPI 適配修復(fù)強(qiáng)制刷新布局 fChromium.Invalidate; fChromium.Repaint; end;5.2 現(xiàn)象TChromium.Load(https://xxx)報ERR_CONNECTION_REFUSED但瀏覽器能打開原因CEF 默認(rèn)啟用代理自動檢測PAC而企業(yè)內(nèi)網(wǎng) PAC 腳本可能返回錯誤代理地址。86.0.23.0 的TCefRequestContext不繼承系統(tǒng)代理。解決顯式禁用代理在GlobalCEFApp初始化后添加GlobalCEFApp.CefArgs.Add(--no-proxy-server); // 關(guān)鍵 GlobalCEFApp.CefArgs.Add(--proxy-serverdirect://);5.3 現(xiàn)象DevToolsF12打開后主頁面 JS 事件全部失效原因devtools_resources.pak版本與libcef.dll不匹配如用了 87.x 的 pak導(dǎo)致 DevTools 進(jìn)程崩潰并拖垮主進(jìn)程。解決嚴(yán)格使用cef_binary_86.0.23.0_windows64.zip中的原始devtools_resources.pak絕不可混用其他版本。5.4 現(xiàn)象調(diào)用myapi.getDeviceInfo返回undefined但 Delphi 端Execute已執(zhí)行原因TCefV8ValueRef.CreateString返回的ICefV8Value在Execute函數(shù)退出后被 GC 回收retval指向野指針。解決改用TCefV8ValueRef.CreateString的Own版本并確保Result : Trueretval : TCefV8ValueRef.CreateString(DeviceInfo).Own; // ← 加 .Own Result : True; // ← 必須顯式設(shè)為 True否則 CEF 忽略 retval5.5 現(xiàn)象程序退出時Access Violation堆棧指向libcef.dll!cef_shutdown原因GlobalCEFApp.Free被調(diào)用兩次——一次在.dpr的Application.Run后一次在TChromium.Destroy中隱式觸發(fā)。解決在.dpr結(jié)尾處顯式置空并禁止二次釋放Application.Run; GlobalCEFApp.Free; GlobalCEFApp : nil; // ← 關(guān)鍵防止 TChromium 析構(gòu)時再調(diào)用6. 進(jìn)階技巧用TCefRequestHandler攔截請求、注入 CSS/JS 與離線資源映射當(dāng)你的應(yīng)用需要攔截所有網(wǎng)絡(luò)請求如統(tǒng)一添加認(rèn)證 Header、在每個頁面注入全局 CSS/JS、或把/api/請求重定向到本地 JSON 文件——這些都不能靠前端 JS 完成必須在 CEF 的網(wǎng)絡(luò)棧底層介入。TCefRequestHandler是 86.23.0 中最靈活的鉤子它工作在 Browser 進(jìn)程比TCefResourceHandler更早觸發(fā)。6.1 創(chuàng)建自定義請求處理器攔截、改寫、偽造響應(yīng)新建一個類繼承TCefRequestHandlerOwntype TMyRequestHandler class(TCefRequestHandlerOwn) protected function OnBeforeResourceLoad(const browser: ICefBrowser; const frame: ICefFrame; const request: ICefRequest; const callback: ICefRequestCallback): Boolean; override; function GetResourceHandler(const browser: ICefBrowser; const frame: ICefFrame; const request: ICefRequest): ICefResourceHandler; override; end; function TMyRequestHandler.OnBeforeResourceLoad(const browser: ICefBrowser; const frame: ICefFrame; const request: ICefRequest; const callback: ICefRequestCallback): Boolean; var Url: string; begin Result : False; // False 允許原請求True 阻止請求 Url : request.GetURL; // 示例1為所有請求添加 X-App-Version Header request.SetHeaderByName(X-App-Version, 86.0.23.0, True); // 示例2攔截 /api/config 請求改為本地文件 if AnsiSameText(Url, https://api.example.com/api/config) then begin request.SetURL(file:// ExtractFilePath(ParamStr(0)) mock_config.json); Result : False; // 改寫 URL 后繼續(xù)加載 end; end; function TMyRequestHandler.GetResourceHandler(const browser: ICefBrowser; const frame: ICefFrame; const request: ICefRequest): ICefResourceHandler; var Url: string; begin Result : nil; Url : request.GetURL; // 示例3將 /css/app.css 映射到本地 assets 目錄 if AnsiStartsText(/css/, Url) then begin Result : TCefStreamResourceHandler.Create( text/css, TFileStream.Create(ExtractFilePath(ParamStr(0)) assets Url, fmOpenRead) ); end else if AnsiStartsText(/js/, Url) then begin // 示例4注入全局 JS如 Sentry SDK Result : TCefStreamResourceHandler.Create( application/javascript, TStringStream.Create(console.log(Injected by Delphi);) ); end; end;然后在TChromium.OnBeforeCreated事件中綁定procedure TMainForm.ChromiumBeforeCreated(Sender: TObject; var aWindowInfo: TCefWindowInfo; var aClient: ICefClient; var aBrowserSettings: TCefBrowserSettings); begin // 綁定自定義請求處理器 aClient : TCefClientRef.Create(TMyRequestHandler.Create); end;技巧說明OnBeforeResourceLoad是第一道關(guān)卡適合 Header 注入、URL 改寫GetResourceHandler是第二道適合完全接管響應(yīng)內(nèi)容如返回 mock JSON、注入 JS、重寫 CSS。二者配合可實(shí)現(xiàn) 100% 離線運(yùn)行——某跨平臺系統(tǒng)正是用此法將所有https://cdn.xxx.com/請求映射到.\cdn\本地目錄徹底擺脫網(wǎng)絡(luò)依賴。6.2 離線資源映射表一份可維護(hù)的 JSON 配置驅(qū)動硬編碼 URL 映射難以維護(hù)。我習(xí)慣用mapping.json文件驅(qū)動{ mappings: [ { pattern: ^https://api\\.example\\.com/api/.*$, target: file://./mock/{path}, type: file }, { pattern: ^https://fonts\\.googleapis\\.com/.*$, target: file://./fonts/, type: dir } ] }在GetResourceHandler中解析此 JSON用System.JSON用正則匹配request.GetURL動態(tài)構(gòu)造本地路徑。這樣前端開發(fā)改 API 地址只需更新 JSON無需重編譯 Delphi。最后說一句CEF4Delphi 86.0.23.0 不是銀彈它吃內(nèi)存、啟動稍慢、調(diào)試鏈路長。但它給了 Delphi 開發(fā)者一條不妥協(xié)的路——不用放棄現(xiàn)有代碼資產(chǎn)就能讓老應(yīng)用長出 Web 的翅膀。我堅(jiān)持在每個新項(xiàng)目里用它不是因?yàn)樗昝蓝且驗(yàn)樗目游叶继诉^它的邊界我都標(biāo)清它值得被認(rèn)真對待。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取