<p>I am currently using the standard lib http.FileServer to serve a directory of assets to my web application.</p>
<p>One of the sub-directories in this directory is a folder of images. At any given point, these images can be overwritten by the user.</p>
<p>The issue is that if the user has loaded the old image at all in their browser, they will be served the old copy rather than the updated file on the server.</p>
<p>I can bust the cache on the client by injecting a URL parameter string on each image reference but I would prefer if I can find a solution where the file is checked for last modify time and serve the fresh copy instead. Not sure if this is related or not but I am using a reverse proxy in front of my server. </p>
<p>I don't want to disable caching on the images entirely, as the images do not change very frequently and the users are constantly refreshing the main table view which results in 50-100 images being requested from the server. Is a URL parameter cache buster really the only solution? Can I explicitly expire the cache for any given resource on save so that I am guaranteed a fresh copy?</p>
<hr/>**评论:**<br/><br/>metamatic: <pre><blockquote>
<p>I would prefer if I can find a solution where the file is checked for last modify time and serve the fresh copy instead.</p>
</blockquote>
<p>Go's http.FileServer already does this. It supports any HTTP client checking the last modification time via an HTTP HEAD request, and only fetching the file if it has changed. You can fire up <a href="https://gist.githubusercontent.com/paulmach/7271283/raw/2a1116ca15e34ee23ac5a3a87e2a626451424993/serve.go" rel="nofollow">a quick server</a> on some temporary files and verify:</p>
<pre><code>% curl -I http://localhost:8100/compelling.png
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 154093
Content-Type: image/png
Last-Modified: Mon, 24 Jul 2017 17:26:46 GMT
Date: Mon, 24 Jul 2017 17:29:32 GMT
</code></pre>
<p>Touch the file, curl again, and you'll see the Last-Modified header is changed.</p>
<blockquote>
<p>I can bust the cache on the client by injecting a URL parameter string on each image reference but I would prefer if I can find a solution where the file is checked for last modify time and serve the fresh copy instead.</p>
</blockquote>
<p>Your server already supports the behavior you want, the problem is that as you've discovered, browsers don't always behave properly. So you're going to have to inject a URL parameter to force the browser to refresh its cache.</p></pre>Virtual-Go: <pre><p>Yeah you are spot on that the server is showing a modified time in the header response, indicating it has changed.</p>
<p>Kinda funny that Google Chrome is the browser ignoring this header. You would think their own browser would handle this response header correctly given the standard lib expects it. I can even access the image URL explicitly and see different images based on the cache busting string I input.</p></pre>Virtual-Go: <pre><p>Even more strange:</p>
<p>I can visit an image URL directly and see the stale image, and then click control+r to refresh and it starts showing the new image. Not sure what a page refresh is doing differently from a direct URL access but it clearly is treated differently in the browser.</p></pre>porkbonk: <pre><p>Can't have it both ways I suppose. Chrome requests a file and remembers the last modified date. Now it's cached.</p>
<p>You visit the same site again and Chrome uses the cache: no request is made. Chrome can't know about the updated file until it actually requests it (ideally including the last modified date, so the server can respond with either 200 or "not modified").</p></pre>Virtual-Go: <pre><p>That seems to defy the point of remembering the last modified date if it never sends another request to determine if the server's version has changed before using the cached value.</p>
<p>What should I do from my perspective to make Chrome check with server before using its cache for these images?</p></pre>porkbonk: <pre><p>Since you can't use <code>Expires</code>.. I'd probably use the URL parameter and set it to the last modified date of the file. It is essentially a different file after it was modified; you might even rename the file itself instead. That way caching still works and you can update any time.</p></pre>porkbonk: <pre><p>http.FileServer uses <a href="https://golang.org/src/net/http/fs.go?s=19273:19313#L152" rel="nofollow">serveContent</a> under the hood. It either sets the <code>Last-Modified</code> header or omits it and replies with a "not modified" status.</p>
<p>Seems to me the browser is not actually making any requests. Have you checked the actual browser behavior when making requests using the browser developer tools?</p>
<p>Anyway, why not set the <code>Expires</code> header to a sensible date in the future? That way it will attempt to fetch the latest version when reaching the expiration date. The HTTP server might respond with "not modified" without sending a body OR simply send the latest version.</p>
<p>EDIT: I don't know what the best practices here are. Feel free to correct me.</p></pre>Virtual-Go: <pre><p>I debated this but the issue the users are specially complaining about is that they modify an image and then generate a report within a few minutes, and the generated report has the stale image. Only way to ensure they never get a stale image is to expire cache immediately using this approach.</p>
<p>I still want the cache to function, except I'd like to immediately expire cache for any image that is updated so it either grabs fresh copy or update image in cache.</p></pre>denise-bryson: <pre><p>I guess this is also meant for <a href="/u/porkbonk" rel="nofollow">u/porkbonk</a></p>
<p>The <em>best practice</em> is to serve files with a completely new url i.e. change the filename e.g. <code>example.com/myfile.$hash.png</code> or add a cache-busting query string e.g. <code>example.com/myfile.png?$hash</code> - preferably the former.</p>
<p>Here <code>$hash</code> could be a md5 hash of the file or hash of the filename and the last modified date if that's too expensive,.</p>
<p>EDIT: you'd then set the appropriate HTTP headers to tell the browser that it can cache these files forever.</p></pre>ask: <pre><p>Add the file timestamp or a checksum into the URL, either as a query parameter or part of the filename. This is basically how it's worked for decades.</p>
<p>The advantage is that then you can tell the browser that it never has to check the file again by setting a far future Expires or very long Cache-Control max-age.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传