从CEFSharp中的缓存中读取文件

时间:2016-05-16 21:08:05

标签: pdf chromium-embedded cefsharp

我需要导航到最终包含.pdf文件的网站,我想在本地保存该文件。我正在使用CEFSharp来做到这一点。此站点的性质是,一旦.pdf出现在浏览器中,就无法再次访问它。出于这个原因,我想知道一旦你在浏览器中显示.pdf,有没有办法在缓存中访问该文件的源?

我尝试过实现IDownloadHandler,但是你必须点击嵌入式.pdf上的保存按钮。我想解决这个问题。

1 个答案:

答案 0 :(得分:9)

好的,这就是我的工作方式。 CEFSharp中有一个功能,允许您过滤传入的Web响应。因此,这使您可以完全访问传入流。我的解决方案有点脏,并不是特别有效,但它适用于我的情况。如果有人看到更好的方式,我愿意接受建议。为了让我的代码能够工作,我必须承担两件事。

  1. 每次下载新页面时都会调用GetResourceResponseFilter。
  2. PDF是导航过程中最后要下载的内容。
  3. 从这里找到的CEF最小示例开始:https://github.com/cefsharp/CefSharp.MinimalExample

    我使用的是WinForms版本。在表单定义中实现IRequestHandler和IResponseFilter,如下所示:

    public partial class BrowserForm : Form, IRequestHandler, IResponseFilter
    {
        public readonly ChromiumWebBrowser browser;
    
        public BrowserForm(string url)
        {
            InitializeComponent();
    
            browser = new ChromiumWebBrowser(url)
            {
                Dock = DockStyle.Fill,
            };
    
            toolStripContainer.ContentPanel.Controls.Add(browser);
            browser.BrowserSettings.FileAccessFromFileUrls = CefState.Enabled;
            browser.BrowserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
            browser.BrowserSettings.WebSecurity = CefState.Disabled;
            browser.BrowserSettings.Javascript = CefState.Enabled;
    
            browser.LoadingStateChanged += OnLoadingStateChanged;
            browser.ConsoleMessage += OnBrowserConsoleMessage;
            browser.StatusMessage += OnBrowserStatusMessage;
            browser.TitleChanged += OnBrowserTitleChanged;
            browser.AddressChanged += OnBrowserAddressChanged;
            browser.FrameLoadEnd += browser_FrameLoadEnd;
    
            browser.LifeSpanHandler = this;
            browser.RequestHandler = this;
    

    声明和最后两行对于此解释是最重要的。我使用这里找到的模板实现了IRequestHandler: https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Example/RequestHandler.cs 除了GetResourceResponseFilter之外,我将所有内容都更改为默认建议,我实现如下:

        IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
        {
            if (request.Url.EndsWith(".pdf"))
                return this;
    
            return null;
        }
    

    然后我按如下方式实施了IResponseFilter:

        FilterStatus IResponseFilter.Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
        {
    
            BinaryWriter sw;
    
            if (dataIn == null)
            {
                dataInRead = 0;
                dataOutWritten = 0;
    
                return FilterStatus.Done;
            }
    
            dataInRead = dataIn.Length;
            dataOutWritten = Math.Min(dataInRead, dataOut.Length);
    
            byte[] buffer = new byte[dataOutWritten];
            int bytesRead = dataIn.Read(buffer, 0, (int)dataOutWritten);
    
            string s = System.Text.Encoding.UTF8.GetString(buffer);
            if (s.StartsWith("%PDF"))
                File.Delete(pdfFileName);
            sw = new BinaryWriter(File.Open(pdfFileName, FileMode.Append));
            sw.Write(buffer);
            sw.Close();
    
            dataOut.Write(buffer, 0, bytesRead);
    
            return FilterStatus.Done;
        }
    
        bool IResponseFilter.InitFilter()
        {
            return true;
        }
    

    我发现PDF在加载时实际上下载了两次。在任何情况下,可能都有标题信息以及页面开头没有的信息。当我得到以%PDF开头的流段时,我知道它是PDF的开头,所以我删除了该文件以丢弃可能存在的任何先前内容。否则,我只是将每个段附加到文件的末尾。从理论上讲,PDF文件在您导航到另一个PDF之前是安全的,但我的建议是在加载页面后立即对文件执行某些操作以确保安全。