C# WebClient 禁用缓存

Posted

技术标签:

【中文标题】C# WebClient 禁用缓存【英文标题】:C# WebClient disable cache 【发布时间】:2011-04-18 05:54:22 【问题描述】:

美好的一天。

我在我的 C# 应用程序中使用 WebClient 类,以便每分钟下载相同的文件,然后应用程序执行一个简单的检查以查看文件是否已更改,以及是否确实与它。

因为这个文件每分钟下载一次,WebClient 缓存系统正在缓存文件,而不是再次下载文件,只是简单地从缓存中获取它,这会妨碍检查下载的文件是否是新的。

所以我想知道如何禁用WebClient 类的缓存系统。

我试过了。

Client.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);

我也尝试了标题。

WebClient.Headers.Add("Cache-Control", "no-cache");

效果不佳。那么如何才能永久禁用缓存呢?

谢谢。

编辑

我还尝试了以下CacheLevelsNoCacheNoStoreBypassCacheReload。没有效果,但是如果我重新启动计算机,缓存似乎已被清除,但我不能每次都重新启动计算机。

针对最近的活动进行更新(2012 年第 8 套)

标记为已接受的answer 解决了我的问题。简单来说,我用 用于下载文件的套接字,这解决了我的问题。基本上是一个 GET 请求所需的文件,我不会详细说明如何做, 因为我相信你可以在 SO in 上找到很多“如何做” 为了自己做同样的事情。虽然这并不意味着我的解决方案也是最适合您的,但我的第一个建议是阅读其他答案,看看是否有用。

无论如何,由于这个问题最近出现了一些活动,我考虑添加此更新以包含一些提示或想法,我认为这些提示或想法应该被那些尝试过的面临类似问题的人考虑 他们能想到的一切,并确定问题不在于 用他们的代码。 可能是大多数情况下的代码,但有时我们只是看不到它,只是去散散步,几分钟后回来,你可能会看到它是最空白的范围首先是显而易见的事情。

无论哪种方式,如果您确定,那么在这种情况下,我建议您检查天气,您的请求会通过其他具有缓存功能的设备(计算机、路由器、代理...),直到它到达预期的目的地。

考虑到大多数请求都通过前面提到的一些此类设备,更多 通常是路由器,当然除非你直接连接到 通过您的服务提供商上网 网络。

有一次我自己的路由器正在缓存文件,我知道很奇怪,但确实如此,每当我重新启动它或直接连接到 Internet 时,我的缓存问题就消失了。而且没有任何其他设备连接到路由器可以受到指责,只有计算机和路由器。

顺便说一下,一个一般性的建议,虽然它主要适用于那些在公司开发计算机而不是自己的计算机上工作的人。可以通过任何更改您的开发计算机运行各种缓存服务吗?这是可能的。

此外,考虑到许多高端网站或服务使用Content Delivery Networks (CDN),并且取决于 CDN 提供商, 每当更新或更改文件时,都需要一些时间 变化反映在整个网络中。因此它可能是 可能你运气不好,要求一个文件可能是 更新中,离你最近的 CDN 服务器 还没更新完。

无论如何,特别是如果您总是一遍又一遍地请求同一个文件,或者如果您找不到问题所在,那么如果可能的话,我建议您重新考虑您的方法一次又一次地请求相同的文件,而是考虑构建一个简单的Web Service,以满足您首先考虑满足此类文件的需求。

如果您正在考虑这样的选择,我认为您可能会更轻松地根据自己的需要构建REST 样式Web API。

我希望此更新在某种程度上对您有用,肯定会在回来时对我有用。祝您的编码工作好运。

【问题讨论】:

您能否举例说明使用无缓存时的请求和响应标头?从你到目前为止所说的来看,它似乎确实应该起作用。 您是否对每个请求使用相同的 WebClient 实例?如果您将其丢弃并每次都创建一个新的会发生什么? @rossisdead:完全一样。 【参考方案1】:

您可以尝试在每次下载文件时将一些随机数字作为查询字符串的一部分附加到您的网址。这确保了 url 每次都是唯一的。

例如-

Random random = new Random();
string url = originalUrl + "?random=" + random.Next().ToString();
webclient.DownloadFile(url, downloadedfileurl);

【讨论】:

@Vinary:我很遗憾地说,即使在文件 url 末尾的参数中使用随机值,也不能像在不使用文件的缓存版本下载文件时那样工作。 这是一个对我来说很棒的天才黑客。但是,我已将其修改为不使用随机数,而是使用从 Environment.TickCount 开始并每次递增的静态数。干杯。 绝对不是这个问题的正确答案,但对于我们所有试图弄清楚如何防止页面的缓存版本出现在 WebBrowser 控件中的人来说肯定非常有帮助。为我工作。 旧答案。但我应该指出随机数正确唯一的最佳方法,您可以使用DateTime.Now.Ticks 我正在使用类似的东西,在每个请求的末尾附加一个 Guid.NewGuid() 。一定要使用吗?或 & 附加参数(或者,在我的情况下,只是使用 # 的假书签)。【参考方案2】:

从上面我猜你在其他地方有问题。你能在服务器端记录http请求吗?当你改变一些随机种子参数时,你会得到什么?

也许 SERVER 缓存了文件(如果日志显示请求确实每分钟触发一次。

您使用 ISA 还是 SQUID?

您的请求的 http 响应代码是什么?

我知道用答案回答可能不受欢迎,但评论不允许我这么多文字:)

编辑:

无论如何,使用HttpRequest 对象而不是WebClient,希望(如果您对WebClient 有疑问)一切都会得到解决。如果HttpRequest 没有解决,那么问题就出在其他地方。

进一步细化:

再往下走:How do I Create an HTTP Request Manually in .Net?

这是纯套接字,如果问题仍然存在,则打开一个新问题并标记它 WTF :)

【讨论】:

@Daniel:关于服务器,一旦它不是我的,我什么都不知道,我不能控制它。但是文件被System.Net 和 IE 缓存,而不是在使用 Firefox 时,我知道因为有时我在我的应用程序中中断 zip 下载导致下载的 zip 损坏,有时这种损坏的 zip 会留在缓存中,并且每个当我的 App 或 IE 再次下载文件时,他会从缓存中下载损坏的版本。但是,如果我使用 Firefox 下载文件,他会以完美的状态下载 zip 文件。 好的,但是对于其他想法呢?您是否有某种涉及的代理服务器? @Daniel:没有使用代理。我也试过通过IE清除缓存,手动也没用。我已经尝试使用WebClient 下载文件,也尝试使用WebRequest,然后将 ResponseStream 保存到文件中,同样的问题,即使使用随机参数技术,它们都使用缓存,并说明每个属性的 CachePolicy不要使用缓存。 Cache-Control 标头也不能正常工作。 @Daniel:我怀疑它会起作用,一旦 HttpWebResquest 和我使用的其他类共享相同的骨干类。基本上它们几乎是一样的。 我不确定这一点,但也不确定不是这样。那么,试试这个:***.com/questions/2109695/…【参考方案3】:

试试NoCacheNoStore:

从不使用缓存中的资源来满足请求,并且不缓存资源。如果资源存在于本地缓存中,则将其删除。此策略级别向中间缓存指示它们应该删除资源。在 HTTP 缓存协议中,这是使用 no-cache 缓存控制指令实现的。

client.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore); 

【讨论】:

@Fabio 可能你必须为此使用 Webrequest BranchCache 服务 (Windows 7) 可能仍然存在冲突 - 将其关闭,测试。 @mhambra:BranchService 是基于本地网络资源的缓存服务,与 Web 资源无关,但是它关闭了,仍然不起作用。 @Fábio Antunes:您能否与我们分享您的确切代码,可能是您调用方法的整个方法?【参考方案4】:

在某些情况下,网络调试软件可能会导致此问题。为了确保您的 url 没有被缓存,您可以附加一个随机数作为最后一个参数以使 url 唯一。在大多数情况下,服务器会忽略此随机参数(尝试读取作为名称值对发送的参数)。

示例: http://www.someserver.com/?param1=val1&ThisIsRandom=RandomValue

ThisIsRandom=RandomValue 是添加的新参数。

【讨论】:

我知道你的意思,如果我尝试下载一个网页,那就行了。在这种情况下是一个文件,其 url 类似于:www.example.com/files/now.zip 这应该仍然有效——即使是 html 以外的请求类型。该网址看起来像 www.example.com/files/now.zip?rand=randomvalue 正如 Dan 所说,它应该适用于所有类型的请求。 @Dan Esparza,Ivymike:你说得对,它奏效了。永远不要在文件 url 末尾使用参数。谢谢。 @Dan Esparza, Ivymike:我很遗憾地说,即使在文件 url 末尾的参数中使用随机值也没有起作用。【参考方案5】:
client.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);

应该可以。 System.Net 运行代码之前,请确保清除缓存并删除 Internet Explorer 中的所有临时下载文件,并且 IE 都使用相同的缓存。

【讨论】:

还是不行。我已经尝试了每一个CacheLevel,它会禁用文件的缓存并且什么都没有,并且清理 IE Temps 也没有任何效果。【参考方案6】:

我在使用 webClient 的 powershell 时遇到了类似的问题,在切换到使用 webRequest 后也出现了这种问题。我发现套接字被重用了,这会导致各种服务器/网络端缓存(在我的情况下,负载平衡器也遇到了问题,尤其是 https 问题)。解决此问题的方法是禁用 webrequest 对象中的 keepalive 和可能的管道,如下所示,这将为每个请求强制一个新的套接字:

#Define Funcs Function httpRequest 
     param([string]$myurl)
     $r = [System.Net.WebRequest]::Create($myurl)
     $r.keepalive = 0
     $sr = new-object System.IO.StreamReader (($r.GetResponse()).GetResponseStream())
     $sr.ReadToEnd() 

【讨论】:

【参考方案7】:

我猜你将不得不使用 webrequest/webresponse 而不是 webclient

    WebRequest request = WebRequest.Create(uri);
     // Define a cache policy for this request only. 
     HttpRequestCachePolicy noCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
     request.CachePolicy = noCachePolicy;
     WebResponse response = request.GetResponse();

//below is the function for downloading the file

   public static int DownloadFile(String remoteFilename,
                           String localFilename)
    
        // Function will return the number of bytes processed
        // to the caller. Initialize to 0 here.
        int bytesProcessed = 0;

        // Assign values to these objects here so that they can
        // be referenced in the finally block
        Stream remoteStream = null;
        Stream localStream = null;
        WebResponse response = null;

        // Use a try/catch/finally block as both the WebRequest and Stream
        // classes throw exceptions upon error
        try
        
            // Create a request for the specified remote file name
            WebRequest request = WebRequest.Create(remoteFilename);
            // Define a cache policy for this request only. 
            HttpRequestCachePolicy noCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
            request.CachePolicy = noCachePolicy;
            if (request != null)
            
                // Send the request to the server and retrieve the
                // WebResponse object 
                response = request.GetResponse();

                if (response != null)
                
                    if (response.IsFromCache)
                        //do what you want

                    // Once the WebResponse object has been retrieved,
                    // get the stream object associated with the response's data
                    remoteStream = response.GetResponseStream();

                    // Create the local file
                    localStream = File.Create(localFilename);

                    // Allocate a 1k buffer
                    byte[] buffer = new byte[1024];
                    int bytesRead;

                    // Simple do/while loop to read from stream until
                    // no bytes are returned
                    do
                    
                        // Read data (up to 1k) from the stream
                        bytesRead = remoteStream.Read(buffer, 0, buffer.Length);

                        // Write the data to the local file
                        localStream.Write(buffer, 0, bytesRead);

                        // Increment total bytes processed
                        bytesProcessed += bytesRead;
                     while (bytesRead > 0);
                
            
        
        catch (Exception e)
        
            Console.WriteLine(e.Message);
        
        finally
        
            // Close the response and streams objects here 
            // to make sure they're closed even if an exception
            // is thrown at some point
            if (response != null) response.Close();
            if (remoteStream != null) remoteStream.Close();
            if (localStream != null) localStream.Close();
        

        // Return total bytes processed to caller.
        return bytesProcessed;
    

【讨论】:

是的。我已经尝试过这种方法,但是我可以将响应保存到文件中。最初的目的是什么。 您是否曾经使用 WebRequest 类下载过文件?您究竟是如何保存文件的? 你试过代码了吗?在我发布这个问题之前,我已经尝试过这种方法但没有奏效.. NullReferenceException at bytesRead = remoteStream.Read(buffer, 0, buffer.Length)。我还尝试替换为“int bytesRead = 0;”同样的问题。 我已经成功修复了将请求保存为流的代码,但是WebRequest 仍在使用缓存来加载文件。【参考方案8】:

使用HTTPRequest 绝对是您问题的正确答案。但是,如果您希望阻止您的 WebBrowser/WebClient 对象使用缓存页面,您不仅应该包含"no-cache",还应该包含所有这些标题:

<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache-control" content="no-store">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">

在 IE11 中,它对我不起作用,直到我包含了最后两个中的一个或两个。

【讨论】:

【参考方案9】:

这里的所有方法似乎都无法解决问题: 如果一个网页曾经可以访问并且现在从服务器中删除,HttpWebResponse.GetResponse() 方法会给你一个缓存副本的响应,以“在足够的时间过去之前,或者你重新启动计算机,它将不触发 404 page not found 错误的预期异常,您无法知道该网页现在根本不存在。

我什么都试过了:

设置标头如 ("Cache-Control", "no-cache") 将“request.CachePolicy”设置为“noCachePolicy” 删除 IE tem/history 文件。 在没有路由器的情况下使用有线互联网............不起作用!

幸运的是,如果网页内容发生了变化,HttpWebResponse.GetResponse() 会给你一个新的页面来反映变化。

【讨论】:

【参考方案10】:

检查您是否受到速率限制!我是从 nginx 服务器获取的:

403 禁止

超出速率限制,请在 24 小时后重试。

这是我使用的程序(C#)

using System;
using System.IO;
using System.Net;

namespace ConsoleApplication1

    class Program
    
        static void Main(string[] args)
        
            DownloadFile();
            Console.ReadLine();
        

        public static void DownloadFile()
        
            var downloadedDatabaseFile = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
            Console.WriteLine(downloadedDatabaseFile);

            var client = new WebClient();
            client.DownloadProgressChanged += (sender, args) =>
            
                Console.WriteLine("0 of 1 2%", args.BytesReceived, args.TotalBytesToReceive, args.ProgressPercentage);
            ;

            client.DownloadFileCompleted += (sender, args) =>
            
                Console.WriteLine("Download file complete");

                if (args.Error != null)
                
                    Console.WriteLine(args.Error.Message);
                
            ;

            client.DownloadFileAsync(new Uri("http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dats.gz"), downloadedDatabaseFile);
        
    

控制台打印出来:

C:\Users\jake.scott.WIN-J8OUFV09HQ8\AppData\Local\Temp\2\tmp7CA.tmp
Download file complete
The remote server returned an error: (403) Forbidden.

【讨论】:

【参考方案11】:

因为我使用以下:

wclient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
wclient.Headers.Add("Cache-Control", "no-cache");

我再也没有缓存文件了。

我还添加了我发现的这个功能,在每次调用之前删除 IE 临时文件:

private void del_IE_files()

    string path = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
    //for deleting files

    System.IO.DirectoryInfo DInfo = new DirectoryInfo(path);
    FileAttributes Attr = DInfo.Attributes;
    DInfo.Attributes = FileAttributes.Normal;

    foreach (FileInfo file in DInfo.GetFiles())
    
        file.Delete();
    

    foreach (DirectoryInfo dir in DInfo.GetDirectories())
    
        try
        
            dir.Delete(true); //delete subdirectories and files
        
        catch
        

        
    

【讨论】:

【参考方案12】:

如果您有权访问网络服务器,请打开 Internet Explorer 转到

Internet Explorer -> Internet Options -> Browsing History "Settings" -> Temporary Internet Files "never"

清除浏览器缓存,瞧,它会工作!

【讨论】:

以上是关于C# WebClient 禁用缓存的主要内容,如果未能解决你的问题,请参考以下文章

使用 WebClient 将带有标头的请求发送到第三方 api

finishConnect(..) 失败:连接被拒绝:localhost/127.0.0.1,错误:Webflux、Webclient、Spring boot、java

禁用 Spring Boot Webclient 日志

Spring boot webclient 2gb xml数据获取io.netty.handler.timeout.ReadTimeoutException:null

有没有办法在 Windows 中使用 C# 以编程方式禁用磁盘驱动器上的写入缓存策略?

如何向 WebClient (C#) 添加证书?