CefSharp自定義緩存實(shí)現(xiàn)
大家好,我是沙漠盡頭的狼。
上文介紹了《C# 使用 CefSharp 內(nèi)嵌網(wǎng)頁(yè) - 并給出 C# 與 JS 的交互示例》,本文介紹 CefSharp 的緩存實(shí)現(xiàn),先來說說添加緩存的好處:
提高頁(yè)面加載加速:CefSharp 緩存可以緩存已經(jīng)加載過的頁(yè)面和資源,當(dāng)用戶再次訪問相同的頁(yè)面時(shí),可以直接從緩存中加載,而不需要重新下載和解析頁(yè)面和資源,從而加快頁(yè)面加載速度。
減少網(wǎng)絡(luò)流量:使用緩存可以減少網(wǎng)絡(luò)流量,因?yàn)橐呀?jīng)下載過的資源可以直接從緩存中讀取,而不需要重新下載。
提高用戶體驗(yàn):由于緩存可以提高頁(yè)面加載速度,因此可以提高用戶的體驗(yàn),用戶可以更快地訪問頁(yè)面和資源,從而更加愉快地使用應(yīng)用程序。
減少服務(wù)器負(fù)載:使用緩存可以減少服務(wù)器的負(fù)載,因?yàn)橐呀?jīng)下載過的資源可以直接從緩存中讀取,而不需要重新生成和發(fā)送。
離線訪問:可以使應(yīng)用程序支持離線訪問,因?yàn)樗梢跃彺嬉呀?jīng)下載過的頁(yè)面和資源,當(dāng)用戶沒有網(wǎng)絡(luò)連接時(shí),可以直接從緩存中加載頁(yè)面和資源。
總之,使用緩存可以提高應(yīng)用程序的性能和用戶體驗(yàn),減少網(wǎng)絡(luò)流量和服務(wù)器負(fù)載,并支持離線訪問,是一個(gè)非常有用的特性。
本文示例:Github
斷網(wǎng)情況下,演示加載已經(jīng)緩存的百度、百度翻譯、Dotnet9 首頁(yè)、Dotnet9 關(guān)于?4 個(gè)頁(yè)面:

接下來講解緩存的實(shí)現(xiàn)方式。
1. 默認(rèn)緩存實(shí)現(xiàn)
CefSharp 的默認(rèn)緩存實(shí)現(xiàn)方式是基于 Chromium 的緩存機(jī)制。Chromium 使用了兩種類型的緩存:內(nèi)存緩存和磁盤緩存。
1.1. 內(nèi)存緩存
內(nèi)存緩存是一個(gè)基于 LRU(最近最少使用)算法的緩存,它緩存了最近訪問的頁(yè)面和資源。內(nèi)存緩存的大小是有限的,當(dāng)緩存達(dá)到最大大小時(shí),最近最少使用的頁(yè)面和資源將被刪除。
內(nèi)存緩存無(wú)法通過 CefSharp.WPF 的 API 進(jìn)行設(shè)置。具體來說,Chromium 會(huì)在內(nèi)存中維護(hù)一個(gè) LRU(Least Recently Used)緩存,用于存儲(chǔ)最近訪問的網(wǎng)頁(yè)數(shù)據(jù)。當(dāng)緩存空間不足時(shí),Chromium 會(huì)根據(jù) LRU 算法自動(dòng)清除最近最少使用的緩存數(shù)據(jù),以騰出空間存儲(chǔ)新的數(shù)據(jù)。
在 CefSharp.WPF 中,我們可以通過調(diào)用 Cef.GetGlobalRequestContext ().ClearCacheAsync () 方法來清除內(nèi)存緩存中的數(shù)據(jù)。該方法會(huì)清除所有緩存數(shù)據(jù),包括內(nèi)存緩存和磁盤緩存。如果只需要清除內(nèi)存緩存,可以調(diào)用 Cef.GetGlobalRequestContext ().ClearCache (CefCacheType.MemoryCache) 方法。
需要注意的是,由于內(nèi)存緩存是由 Chromium 自身維護(hù)的,因此我們無(wú)法直接控制其大小。如果需要控制緩存大小,可以通過設(shè)置磁盤緩存的大小來間接控制內(nèi)存緩存的大小。
1.2. 磁盤緩存
磁盤緩存是一個(gè)基于文件系統(tǒng)的緩存,它緩存了已經(jīng)下載的頁(yè)面和資源。磁盤緩存的大小也是有限的,當(dāng)緩存達(dá)到最大大小時(shí),最早的頁(yè)面和資源將被刪除。
CefSharp.WPF 的磁盤緩存是通過設(shè)置 CefSettings 中的 CachePath 屬性來實(shí)現(xiàn)的。具體來說,我們可以通過以下代碼設(shè)置磁盤緩存的路徑:
public partial class App : Application{ ? ?protected override void OnStartup(StartupEventArgs e)
? ?{ ? ? ? ?base.OnStartup(e); ? ? ? ?// CachePath需要為絕對(duì)路徑
? ? ? ?var settings = new CefSettings
? ? ? ?{
? ? ? ? ? ?CachePath = $"{AppDomain.CurrentDomain.BaseDirectory}DefaultCaches"
? ? ? ?};
? ? ? ?Cef.Initialize(settings);
? ?}
}
緩存目錄結(jié)構(gòu)如下:

其中,CachePath 屬性指定了磁盤緩存的路徑(絕對(duì)路徑)。如果不設(shè)置該屬性,Chromium 會(huì)將緩存數(shù)據(jù)存儲(chǔ)在默認(rèn)路徑下(通常是用戶目錄下的 AppData\Local\CefSharp 目錄)。
需要注意的是,磁盤緩存的大小是由 Chromium 自身控制的,我們可以通過設(shè)置 CacheController 的 SetCacheLimit 方法來控制緩存數(shù)據(jù)存儲(chǔ)在磁盤上的最大空間。該方法接受一個(gè) long 類型的參數(shù),表示緩存數(shù)據(jù)的最大大?。▎挝粸樽止?jié))。例如,以下代碼將磁盤緩存的最大大小設(shè)置為 100MB:
var cacheController = Cef.GetGlobalRequestContext().CacheController;cacheController.SetCacheLimit(100 * 1024 * 1024); // 100MB
需要注意的是,Chromium 會(huì)根據(jù) LRU 算法自動(dòng)清除最近最少使用的緩存數(shù)據(jù),以騰出空間存儲(chǔ)新的數(shù)據(jù)。因此,即使設(shè)置了緩存大小,也不能保證所有數(shù)據(jù)都會(huì)被緩存。如果需要清除磁盤緩存中的數(shù)據(jù),可以調(diào)用 Cef.GetGlobalRequestContext ().ClearCacheAsync () 方法。
默認(rèn)的緩存站長(zhǎng)研究不多,上面的代碼和描述通過 ChatGPT 搜索得來,我們來看自定義緩存的實(shí)現(xiàn),默認(rèn)緩存只是個(gè)引子。
2. 自定義緩存
這是本文介紹的重點(diǎn),相對(duì)于默認(rèn)緩存,自定義緩存
有以下好處:
更加靈活:可以根據(jù)應(yīng)用程序的需求來靈活地配置緩存策略和緩存大小,從而更好地滿足應(yīng)用程序的需求。
更好的性能:可以根據(jù)應(yīng)用程序的需求和特定的場(chǎng)景進(jìn)行配置,以獲得更好的性能。默認(rèn)的緩存可能不適合某些特定的場(chǎng)景或者不適合您的應(yīng)用程序的需求,而自定義緩存則可以根據(jù)您的需求進(jìn)行調(diào)整,以獲得更好的性能。
更好的安全性:可以更好地保護(hù)用戶的隱私和安全,因?yàn)榭梢钥刂凭彺嬷写鎯?chǔ)的內(nèi)容和緩存的生命周期。
更加可控:可以更好地控制緩存的行為,例如可以控制緩存的清除時(shí)間和清除策略,從而更好地管理緩存。
更好的兼容性:可以更好地適應(yīng)不同的瀏覽器和設(shè)備,默認(rèn)的緩存可能不能提供足夠的兼容性,而自定義緩存則可以根據(jù)您的需求進(jìn)行調(diào)整,以提供更好的兼容性。
更加高效:可以更好地利用系統(tǒng)資源,例如可以使用更快的存儲(chǔ)設(shè)備來存儲(chǔ)緩存,從而提高緩存的讀寫速度。
總結(jié):自定義緩存可以提供更好的性能、響應(yīng)性、安全性和兼容性,從而提高應(yīng)用程序的質(zhì)量和用戶體驗(yàn),人話就是更好的操控
。
2.1. 代碼實(shí)現(xiàn)
注釋前面加的默認(rèn)緩存代碼。
2.1.1. 注冊(cè)資源請(qǐng)求攔截處理程序
首先在使用?ChromiumWebBrowser
?控件的后臺(tái)代碼里,注冊(cè)請(qǐng)求攔截處理程序,CefBrowser
?是控件名,CefRequestHandlerc
?是處理程序:
public TestCefCacheView(){
? ?InitializeComponent(); ? ?var handler = new CefRequestHandlerc();
? ?CefBrowser.RequestHandler = handler;
}
2.1.2. 請(qǐng)求攔截處理程序
CefSharp 里的?IRequestHandler
?是一個(gè)接口,用于處理瀏覽器發(fā)出的請(qǐng)求。它定義了一些方法,可以在請(qǐng)求被發(fā)送到服務(wù)器之前或之后對(duì)請(qǐng)求進(jìn)行處理。
IRequestHandler
?的實(shí)現(xiàn)類可以用于以下幾個(gè)方面:
攔截請(qǐng)求:可以通過實(shí)現(xiàn) OnBeforeBrowse 方法來攔截請(qǐng)求,從而控制瀏覽器的行為。例如,可以在請(qǐng)求被發(fā)送到服務(wù)器之前檢查請(qǐng)求的 URL,如果不符合要求,則可以取消請(qǐng)求或者重定向到其他頁(yè)面。
修改請(qǐng)求:可以通過實(shí)現(xiàn) OnBeforeResourceLoad 方法來修改請(qǐng)求,例如可以添加一些自定義的 HTTP 頭信息,或者修改請(qǐng)求的 URL。
處理響應(yīng):可以通過實(shí)現(xiàn) OnResourceResponse 方法來處理服務(wù)器返回的響應(yīng),例如可以檢查響應(yīng)的狀態(tài)碼和內(nèi)容,從而決定是否繼續(xù)加載頁(yè)面。
緩存控制:可以通過實(shí)現(xiàn) OnQuotaRequest 方法來控制緩存的大小和清除策略,從而優(yōu)化緩存的使用。
總之,IRequestHandler
?的實(shí)現(xiàn)類可以用于控制瀏覽器的行為,優(yōu)化網(wǎng)絡(luò)請(qǐng)求和緩存的使用,從而提高應(yīng)用程序的性能和用戶體驗(yàn)。
我們不直接實(shí)現(xiàn)接口?IRequestHandler
,而是繼承它的一個(gè)默認(rèn)實(shí)現(xiàn)類?RequestHandler
,這可以簡(jiǎn)化我們的開發(fā),畢竟實(shí)現(xiàn)接口要列出一系列接口方法。
我們重載方法?GetResourceRequestHandler
, 在這個(gè)方法里返回?CefResourceRequestHandler
?實(shí)例,頁(yè)面中資源請(qǐng)求時(shí)會(huì)調(diào)用此方法:
using CefSharp;using CefSharp.Handler;namespace WpfWithCefSharpCacheDemo.Caches;internal class CefRequestHandlerc : RequestHandler{ ? ?protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame,
? ? ? ?IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
? ?{ ? ? ? ?// 一個(gè)請(qǐng)求用一個(gè)CefResourceRequestHandler
? ? ? ?return new CefResourceRequestHandler();
? ?}
}
2.1.3. 資源請(qǐng)求攔截程序
在 CefSharp 中,IResourceRequestHandler
?接口是用于處理資源請(qǐng)求的,它可以攔截瀏覽器發(fā)出的資源請(qǐng)求,例如圖片、CSS、JavaScript 等,從而實(shí)現(xiàn)對(duì)資源請(qǐng)求的控制和優(yōu)化。
具體來說,IResourceRequestHandler
?接口定義了一些方法,例如?OnBeforeResourceLoad
、OnResourceResponse
?等方法,這些方法可以用于攔截請(qǐng)求、修改請(qǐng)求、處理響應(yīng)等方面。例如:
OnBeforeResourceLoad:在瀏覽器請(qǐng)求資源之前被調(diào)用,可以用于修改請(qǐng)求,例如添加一些自定義的 HTTP 頭信息,或者修改請(qǐng)求的 URL。
OnResourceResponse:在瀏覽器接收到服務(wù)器返回的響應(yīng)之后被調(diào)用,可以用于處理響應(yīng),例如檢查響應(yīng)的狀態(tài)碼和內(nèi)容,從而決定是否繼續(xù)加載頁(yè)面。
OnResourceLoadComplete:在資源加載完成后被調(diào)用,可以用于處理資源加載完成后的操作,例如保存資源到本地緩存。
通過實(shí)現(xiàn)?IResourceRequestHandler
?接口,可以對(duì)資源請(qǐng)求進(jìn)行攔截和優(yōu)化,從而提高應(yīng)用程序的性能和用戶體驗(yàn)。
這里我們也不直接實(shí)現(xiàn)?IResourceRequestHandler
?接口,我們定義?CefResourceRequestHandler
?類,繼承該接口的默認(rèn)實(shí)現(xiàn)類?ResourceRequestHandler
。
在下面的?CefResourceRequestHandler
?類中:
GetResourceHandler
?方法:處理資源是否需要緩存,返回 null 不緩存,返回?CefResourceHandler
?表示需要緩存,在這個(gè)類中做跨域處理。GetResourceResponseFilter
?方法:注冊(cè)資源緩存的操作類,即資源下載的實(shí)現(xiàn)。OnBeforeResourceLoad
?方法:在這個(gè)方法里,我們可以實(shí)現(xiàn)給頁(yè)面?zhèn)鬟f header 參數(shù)。
using System.Collections.Specialized;using CefSharp;using CefSharp.Handler;namespace WpfWithCefSharpCacheDemo.Caches;internal class CefResourceRequestHandler : ResourceRequestHandler{ ? ?private string _localCacheFilePath; ? ?private bool IsLocalCacheFileExist => System.IO.File.Exists(_localCacheFilePath); ? ?protected override IResourceHandler? GetResourceHandler(IWebBrowser chromiumWebBrowser, IBrowser browser,
? ? ? ?IFrame frame, IRequest request)
? ?{ ? ? ? ?try
? ? ? ?{
? ? ? ? ? ?_localCacheFilePath = CacheFileHelper.CalculateResourceFileName(request.Url, request.ResourceType); ? ? ? ? ? ?if (string.IsNullOrWhiteSpace(_localCacheFilePath))
? ? ? ? ? ?{ ? ? ? ? ? ? ? ?return null;
? ? ? ? ? ?}
? ? ? ?} ? ? ? ?catch
? ? ? ?{ ? ? ? ? ? ?return null;
? ? ? ?} ? ? ? ?if (!IsLocalCacheFileExist)
? ? ? ?{ ? ? ? ? ? ?return null;
? ? ? ?} ? ? ? ?return new CefResourceHandler(_localCacheFilePath);
? ?} ? ?protected override IResponseFilter? GetResourceResponseFilter(IWebBrowser chromiumWebBrowser, IBrowser browser,
? ? ? ?IFrame frame,
? ? ? ?IRequest request, IResponse response)
? ?{ ? ? ? ?return IsLocalCacheFileExist ? null : new CefResponseFilter { LocalCacheFilePath = _localCacheFilePath };
? ?} ? ?protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser,
? ? ? ?IFrame frame, IRequest request,
? ? ? ?IRequestCallback callback)
? ?{ ? ? ? ?var headers = new NameValueCollection(request.Headers);
? ? ? ?headers["Authorization"] = "Bearer xxxxxx.xxxxx.xxx";
? ? ? ?request.Headers = headers; ? ? ? ?return CefReturnValue.Continue;
? ?}
}
2.1.4. CefResourceHandler
在 CefSharp 中,IResourceHandler
?接口是用于處理資源的,它可以攔截瀏覽器發(fā)出的資源請(qǐng)求,并返回自定義的資源內(nèi)容,從而實(shí)現(xiàn)對(duì)資源的控制和優(yōu)化。
具體來說,IResourceHandler
?接口定義了一些方法,例如?ProcessRequest
、GetResponseHeaders
、ReadResponse
?等方法,這些方法可以用于處理資源請(qǐng)求、獲取響應(yīng)頭信息、讀取響應(yīng)內(nèi)容等方面。例如:
ProcessRequest:在瀏覽器請(qǐng)求資源時(shí)被調(diào)用,可以用于處理資源請(qǐng)求,例如從本地緩存中讀取資源內(nèi)容,或者從網(wǎng)絡(luò)中下載資源內(nèi)容。
GetResponseHeaders:在瀏覽器請(qǐng)求資源時(shí)被調(diào)用,可以用于獲取響應(yīng)頭信息,例如設(shè)置響應(yīng)的 MIME 類型、緩存策略等。
ReadResponse:在瀏覽器請(qǐng)求資源時(shí)被調(diào)用,可以用于讀取響應(yīng)內(nèi)容,例如從本地緩存中讀取資源內(nèi)容,或者從網(wǎng)絡(luò)中下載資源內(nèi)容。
通過實(shí)現(xiàn) IResourceHandler 接口,可以對(duì)資源進(jìn)行自定義處理,例如從本地緩存中讀取資源內(nèi)容,從而提高應(yīng)用程序的性能和用戶體驗(yàn)。
這里我們也不直接實(shí)現(xiàn)?IResourceHandler
?接口,我們定義?CefResourceHandler
?類,繼承該接口的默認(rèn)實(shí)現(xiàn)類?ResourceHandler
。
在?CefResourceHandler
?的構(gòu)造函數(shù)里只處理跨域問題,其他需求可通過上面接口的方法查找資料處理即可:
using CefSharp;using System.IO;namespace WpfWithCefSharpCacheDemo.Caches;internal class CefResourceHandler : ResourceHandler{ ? ?public CefResourceHandler(string filePath, string mimeType = null, bool autoDisposeStream = false, ? ? ? ?string charset = null) : base()
? ?{ ? ? ? ?if (string.IsNullOrWhiteSpace(mimeType))
? ? ? ?{ ? ? ? ? ? ?var fileExtension = Path.GetExtension(filePath);
? ? ? ? ? ?mimeType = Cef.GetMimeType(fileExtension);
? ? ? ? ? ?mimeType = mimeType ?? DefaultMimeType;
? ? ? ?} ? ? ? ?var stream = File.OpenRead(filePath);
? ? ? ?StatusCode = 200;
? ? ? ?StatusText = "OK";
? ? ? ?MimeType = mimeType;
? ? ? ?Stream = stream;
? ? ? ?AutoDisposeStream = autoDisposeStream;
? ? ? ?Charset = charset;
? ? ? ?Headers.Add("Access-Control-Allow-Origin", "*");
? ?}
}
2.1.5. CefResponseFilter
在 CefSharp 中,IResponseFilter
?接口是用于過濾響應(yīng)內(nèi)容的,它可以攔截瀏覽器接收到的響應(yīng)內(nèi)容,并對(duì)其進(jìn)行修改或者過濾,從而實(shí)現(xiàn)對(duì)響應(yīng)內(nèi)容的控制和優(yōu)化。
具體來說,IResponseFilter
?接口定義了一些方法,例如?InitFilter
、Filter
、GetSize
?等方法,這些方法可以用于初始化過濾器、過濾響應(yīng)內(nèi)容、獲取過濾后的響應(yīng)內(nèi)容大小等方面。例如:
InitFilter:在瀏覽器接收到響應(yīng)內(nèi)容時(shí)被調(diào)用,可以用于初始化過濾器,例如設(shè)置過濾器的狀態(tài)、獲取響應(yīng)頭信息等。
Filter:在瀏覽器接收到響應(yīng)內(nèi)容時(shí)被調(diào)用,可以用于過濾響應(yīng)內(nèi)容,例如修改響應(yīng)內(nèi)容、刪除響應(yīng)內(nèi)容等。
GetSize:在瀏覽器接收到響應(yīng)內(nèi)容時(shí)被調(diào)用,可以用于獲取過濾后的響應(yīng)內(nèi)容大小,例如用于計(jì)算響應(yīng)內(nèi)容的壓縮比例等。
站長(zhǎng)使用的?CefSharp.Wpf
?的?89.0.170.0
?版本中的?IResponseFilter
?接口沒有?GetSize
?方法。在該版本中,IResponseFilter
?接口只定義了兩個(gè)方法:InitFilter
?和?Filter
。
如果在該版本中您需要獲取過濾后的響應(yīng)內(nèi)容大小,可以考慮在?Filter
?方法中自行計(jì)算。例如,在?Filter
?方法中,您可以將過濾后的響應(yīng)內(nèi)容寫入一個(gè)緩沖區(qū),并記錄緩沖區(qū)的大小,最后返回過濾后的響應(yīng)內(nèi)容和緩沖區(qū)的大小。
public class MyResponseFilter : IResponseFilter{ ? ?private MemoryStream outputStream = new MemoryStream(); ? ?public void Dispose()
? ?{
? ? ? ?outputStream.Dispose();
? ?} ? ?public bool InitFilter()
? ?{ ? ? ? ?return true;
? ?} ? ?public FilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
? ?{
? ? ? ?dataInRead = 0;
? ? ? ?dataOutWritten = 0; ? ? ? ?byte[] buffer = new byte[4096]; ? ? ? ?int bytesRead = 0; ? ? ? ?do
? ? ? ?{
? ? ? ? ? ?bytesRead = dataIn.Read(buffer, 0, buffer.Length); ? ? ? ? ? ?if (bytesRead > 0)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?outputStream.Write(buffer, 0, bytesRead);
? ? ? ? ? ?}
? ? ? ?} while (bytesRead > 0); ? ? ? ?byte[] outputBytes = outputStream.ToArray();
? ? ? ?dataOut.Write(outputBytes, 0, outputBytes.Length);
? ? ? ?dataInRead = outputBytes.Length;
? ? ? ?dataOutWritten = outputBytes.Length; ? ? ? ?return FilterStatus.Done;
? ?} ? ?public int GetResponseFilterBufferSize()
? ?{ ? ? ? ?return 0;
? ?} ? ?public int GetResponseFilterDelay()
? ?{ ? ? ? ?return 0;
? ?}
}
在上述示例代碼中,我們?cè)?Filter
?方法中將過濾后的響應(yīng)內(nèi)容寫入了一個(gè)?MemoryStream
?對(duì)象中,并記錄了緩沖區(qū)的大小。最后,我們?cè)?Filter 方法的返回值中返回了過濾后的響應(yīng)內(nèi)容和緩沖區(qū)的大小。
總結(jié),通過實(shí)現(xiàn)?IResponseFilter
?接口,可以對(duì)響應(yīng)內(nèi)容進(jìn)行自定義處理,例如對(duì)響應(yīng)內(nèi)容進(jìn)行壓縮、加密等操作,從而提高應(yīng)用程序的性能和安全性。
本文示例這里定義類?CefResponseFilter
?直接實(shí)現(xiàn)接口處理文件緩存實(shí)際操作類,即資源下載實(shí)現(xiàn):
using CefSharp;using System.IO;namespace WpfWithCefSharpCacheDemo.Caches;internal class CefResponseFilter : IResponseFilter{ ? ?public string LocalCacheFilePath { get; set; } ? ?private const int BUFFER_LENGTH = 1024; ? ?private bool isFailCacheFile; ? ?public FilterStatus Filter(Stream? dataIn, out long dataInRead, Stream? dataOut, out long dataOutWritten)
? ?{
? ? ? ?dataInRead = 0;
? ? ? ?dataOutWritten = 0; ? ? ? ?if (dataIn == null)
? ? ? ?{ ? ? ? ? ? ?return FilterStatus.NeedMoreData;
? ? ? ?} ? ? ? ?var length = dataIn.Length; ? ? ? ?var data = new byte[BUFFER_LENGTH]; ? ? ? ?var count = dataIn.Read(data, 0, BUFFER_LENGTH);
? ? ? ?dataInRead = count;
? ? ? ?dataOutWritten = count;
? ? ? ?dataOut?.Write(data, 0, count); ? ? ? ?try
? ? ? ?{
? ? ? ? ? ?CacheFile(data, count);
? ? ? ?} ? ? ? ?catch
? ? ? ?{ ? ? ? ? ? ?// ignored
? ? ? ?} ? ? ? ?return length == dataIn.Position ? FilterStatus.Done : FilterStatus.NeedMoreData;
? ?} ? ?public bool InitFilter()
? ?{ ? ? ? ?try
? ? ? ?{ ? ? ? ? ? ?var dirPath = Path.GetDirectoryName(LocalCacheFilePath); ? ? ? ? ? ?if (!string.IsNullOrWhiteSpace(dirPath) && !Directory.Exists(dirPath))
? ? ? ? ? ?{
? ? ? ? ? ? ? ?Directory.CreateDirectory(dirPath);
? ? ? ? ? ?}
? ? ? ?} ? ? ? ?catch
? ? ? ?{ ? ? ? ? ? ?// ignored
? ? ? ?} ? ? ? ?return true;
? ?} ? ?public void Dispose()
? ?{
? ?} ? ?private void CacheFile(byte[] data, int count)
? ?{ ? ? ? ?if (isFailCacheFile)
? ? ? ?{ ? ? ? ? ? ?return;
? ? ? ?} ? ? ? ?try
? ? ? ?{ ? ? ? ? ? ?if (!File.Exists(LocalCacheFilePath))
? ? ? ? ? ?{ ? ? ? ? ? ? ? ?using var fs = File.Create(LocalCacheFilePath);
? ? ? ? ? ? ? ?fs.Write(data, 0, count);
? ? ? ? ? ?} ? ? ? ? ? ?else
? ? ? ? ? ?{ ? ? ? ? ? ? ? ?using var fs = File.Open(LocalCacheFilePath, FileMode.Append);
? ? ? ? ? ? ? ?fs.Write(data,0,count);
? ? ? ? ? ?}
? ? ? ?} ? ? ? ?catch
? ? ? ?{
? ? ? ? ? ?isFailCacheFile = true;
? ? ? ? ? ?File.Delete(LocalCacheFilePath);
? ? ? ?}
? ?}
}
2.1.6. CacheFileHelper
緩存文件幫助類,用于管理頁(yè)面的 ajax 接口緩存白名單、緩存文件路徑規(guī)范等:
using CefSharp;using System;using System.Collections.Generic;using System.IO;namespace WpfWithCefSharpCacheDemo.Caches;internal static class CacheFileHelper{ ? ?private const string DEV_TOOLS_SCHEME = "devtools"; ? ?private const string DEFAULT_INDEX_FILE = "index.html"; ? ?private static HashSet<string> needInterceptedAjaxInterfaces = new(); ? ?private static string CachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "caches"); ? ?public static void AddInterceptedAjaxInterfaces(string url)
? ?{ ? ? ? ?if (needInterceptedAjaxInterfaces.Contains(url))
? ? ? ?{ ? ? ? ? ? ?return;
? ? ? ?}
? ? ? ?needInterceptedAjaxInterfaces.Add(url);
? ?} ? ?private static bool IsNeedInterceptedAjaxInterface(string url, ResourceType resourceType)
? ?{ ? ? ? ?var uri = new Uri(url); ? ? ? ?if (DEV_TOOLS_SCHEME == url)
? ? ? ?{ ? ? ? ? ? ?return false;
? ? ? ?} ? ? ? ?if (ResourceType.Xhr == resourceType && !needInterceptedAjaxInterfaces.Contains(url))
? ? ? ?{ ? ? ? ? ? ?return false;
? ? ? ?} ? ? ? ?return true;
? ?} ? ?public static string? CalculateResourceFileName(string url, ResourceType resourceType)
? ?{ ? ? ? ?if (!IsNeedInterceptedAjaxInterface(url, resourceType))
? ? ? ?{ ? ? ? ? ? ?return default;
? ? ? ?} ? ? ? ?var uri = new Uri(url); ? ? ? ?var urlPath = uri.LocalPath; ? ? ? ?if (urlPath.StartsWith("/"))
? ? ? ?{
? ? ? ? ? ?urlPath = urlPath.Substring(1);
? ? ? ?} ? ? ? ?var subFilePath = urlPath; ? ? ? ?if (ResourceType.MainFrame == resourceType || string.IsNullOrWhiteSpace(urlPath))
? ? ? ?{
? ? ? ? ? ?subFilePath = Path.Combine(urlPath, DEFAULT_INDEX_FILE);
? ? ? ?} ? ? ? ?var hostCachePath = Path.Combine(CachePath, uri.Host); ? ? ? ?var fullFilePath = Path.Combine(hostCachePath, subFilePath); ? ? ? ?return fullFilePath;
? ?}
}
自定義緩存的子目錄以資源的域名 (Host) 為目錄名稱創(chuàng)建:

打開緩存的?dotnet9.com?目錄,通過查看目錄結(jié)構(gòu)和程序發(fā)布目錄基本一致,這更適合人看了,是不?

2.2. 可能存在的問題
第一點(diǎn),站長(zhǎng)目前遇到的問題,后面 4 點(diǎn)由?Token AI?提供解釋。
2.2.1. 對(duì)緩存的資源 URL 帶 QueryString 的方式支持不好
建議用 Route (路由的方式:https://dotnet9.com/albums/wpf) 代替 QueryString (查詢參數(shù)的試工:https://dotnet9.com/albums?slug=wpf) 的方式,站長(zhǎng)有空再研究下 QueryString 的緩存方式。
如果確實(shí)資源帶 QueryString,那對(duì)于這種資源就放開緩存,直接通過網(wǎng)絡(luò)請(qǐng)求吧。
2.2.2. 緩存一致性問題
如果自定義緩存不正確地處理了緩存一致性,可能會(huì)導(dǎo)致瀏覽器顯示過期的內(nèi)容或者不一致的內(nèi)容。例如,如果緩存了一個(gè)網(wǎng)頁(yè),但是該網(wǎng)頁(yè)在服務(wù)器上已經(jīng)被更新了,如果自定義緩存沒有正確地處理緩存一致性,可能會(huì)導(dǎo)致瀏覽器顯示過期的網(wǎng)頁(yè)內(nèi)容。
2.2.3. 緩存空間問題
如果自定義緩存沒有正確地管理緩存空間,可能會(huì)導(dǎo)致瀏覽器占用過多的內(nèi)存或者磁盤空間。例如,如果自定義緩存緩存了大量的數(shù)據(jù),但是沒有及時(shí)清理過期的數(shù)據(jù)或者限制緩存的大小,可能會(huì)導(dǎo)致瀏覽器占用過多的內(nèi)存或者磁盤空間。
2.2.4. 緩存性能問題
如果自定義緩存沒有正確地處理緩存性能,可能會(huì)導(dǎo)致瀏覽器的性能下降。例如,如果自定義緩存沒有正確地處理緩存的讀取和寫入,可能會(huì)導(dǎo)致瀏覽器的響應(yīng)速度變慢。
2.2.5. 緩存安全問題
如果自定義緩存沒有正確地處理緩存安全,可能會(huì)導(dǎo)致瀏覽器的安全性受到威脅。例如,如果自定義緩存緩存了敏感數(shù)據(jù),但是沒有正確地處理緩存的加密和解密,可能會(huì)導(dǎo)致敏感數(shù)據(jù)泄露。
因此,在自定義緩存時(shí),需要注意處理緩存一致性、緩存空間、緩存性能和緩存安全等問題,以確保瀏覽器的正常運(yùn)行和安全性。
參考:
CefSharp
關(guān)于 CefSharp 中 C# 與 JS 函數(shù)互相調(diào)用的應(yīng)用