Pdf 从CEFSharp中的缓存中读取文件

Pdf 从CEFSharp中的缓存中读取文件,pdf,chromium-embedded,cefsharp,Pdf,Chromium Embedded,Cefsharp,我需要导航到最终包含.pdf文件的网站,并希望将该文件保存在本地。我正在使用CEFSharp来做这件事。此网站的性质是,一旦.pdf出现在浏览器中,就无法再次访问它。出于这个原因,我想知道一旦浏览器中显示了.pdf文件,是否有办法访问缓存中该文件的源文件 我已经尝试过实现IDownloadHandler,这很有效,但是您必须单击embedded.pdf上的save按钮。我正在努力解决这个问题。好的,下面是我如何让它工作的。CEFSharp中有一个函数,允许您过滤传入的web响应。因此,这使您能够

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


我已经尝试过实现IDownloadHandler,这很有效,但是您必须单击embedded.pdf上的save按钮。我正在努力解决这个问题。

好的,下面是我如何让它工作的。CEFSharp中有一个函数,允许您过滤传入的web响应。因此,这使您能够完全访问传入流。我的解决方案有点脏,效率不高,但它适合我的情况。如果有人看到更好的方法,我愿意听取建议。为了让代码正常工作,我必须假设两件事

每次下载新页面时都会调用GetResourceResponseFilter。 PDF是导航过程中最后要下载的内容。 从以下CEF最小示例开始:

我使用了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;
    IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (request.Url.EndsWith(".pdf"))
            return this;

        return null;
    }
    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;
    }
声明和最后两行对于这个解释来说是最重要的。我使用以下模板实现了IRequestHandler: 除了GetResourceResponseFilter之外,我将所有内容都更改为它推荐的默认设置,我实现了如下:

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;
    IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (request.Url.EndsWith(".pdf"))
            return this;

        return null;
    }
    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;
    }
然后,我实现了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;
    IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (request.Url.EndsWith(".pdf"))
            return this;

        return null;
    }
    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文件是安全的,但我的建议是在加载页面后立即对该文件进行处理,以确保安全。

好的,下面是我如何使其工作的。CEFSharp中有一个函数,允许您过滤传入的web响应。因此,这使您能够完全访问传入流。我的解决方案有点脏,效率不高,但它适合我的情况。如果有人看到更好的方法,我愿意听取建议。为了让代码正常工作,我必须假设两件事

每次下载新页面时都会调用GetResourceResponseFilter。 PDF是导航过程中最后要下载的内容。 从以下CEF最小示例开始:

我使用了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;
    IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (request.Url.EndsWith(".pdf"))
            return this;

        return null;
    }
    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;
    }
声明和最后两行对于这个解释来说是最重要的。我使用以下模板实现了IRequestHandler: 除了GetResourceResponseFilter之外,我将所有内容都更改为它推荐的默认设置,我实现了如下:

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;
    IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (request.Url.EndsWith(".pdf"))
            return this;

        return null;
    }
    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;
    }
然后,我实现了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;
    IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        if (request.Url.EndsWith(".pdf"))
            return this;

        return null;
    }
    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之前是安全的,但我的建议是在加载页面后立即对该文件进行处理以确保安全。

CEF没有提供访问缓存的方法,您可能可以直接读取数据库,尽管我从未尝试过。您可以实现ResourceHandler并自己下载文件,在本地缓存它。ResourceHandler的实现根据您使用的分支略有不同。请参阅应该是一个起点,如果您使用的是旧版本,只需切换分支即可查看不同的版本。我在使用.Net WebBrowser的项目的早期版本中尝试过这种方法。我遇到的问题是,创建的HTMLRequest没有cookies或任何安全信息来访问.pdf。有没有办法将浏览器中缓存的安全信息传递给HTMLRequest?我想您可以查询cookie存储,尽管这会变得越来越复杂。还有另一种选择,虽然非常新,而且没有经过特别的测试。看,我想那是票。我可以实现一个基本上是直通式响应过滤器的功能,它可以检查PDF头并在s之前将其保存在本地
在途中结束溪流。有没有一种方法可以在不实现整个IRequestHandler的情况下将其连接起来?我实现了直通响应过滤器。在页面上的某一点上,dataIn.Length将超过dataOut.Length。我尝试通过dataIn.CopyTodataOut,intdataoutwrited来修复这个问题;我仍然得到System.NotSupportedException:无法将此流的长度扩展到其容量之外。CEF不提供访问缓存的方法您可能可以直接读取数据库,尽管我从未尝试过。您可以实现ResourceHandler并自己下载文件,在本地缓存它。ResourceHandler的实现根据您使用的分支略有不同。请参阅应该是一个起点,如果您使用的是旧版本,只需切换分支即可查看不同的版本。我在使用.Net WebBrowser的项目的早期版本中尝试过这种方法。我遇到的问题是,创建的HTMLRequest没有cookies或任何安全信息来访问.pdf。有没有办法将浏览器中缓存的安全信息传递给HTMLRequest?我想您可以查询cookie存储,尽管这会变得越来越复杂。还有另一种选择,虽然非常新,而且没有经过特别的测试。看,我想那是票。我可以实现一个基本上是直通式响应过滤器的功能,它在发送流之前检查PDF头并将其保存在本地。有没有一种方法可以在不实现整个IRequestHandler的情况下将其连接起来?我实现了直通响应过滤器。在页面上的某一点上,dataIn.Length将超过dataOut.Length。我尝试通过dataIn.CopyTodataOut,intdataoutwrited来修复这个问题;我仍然得到System.NotSupportedException:无法将此流的长度扩展到超出其容量。完美解决方案完美解决方案