ASP.net ashx handler not caching

时光毁灭记忆、已成空白 提交于 2019-12-10 11:47:33

问题


We recently installed Robohash as a great fallback for Gravatar:

http://static2.scirra.net/avatars/128/5df4bf5d460c9497fdb35578e923ad1f.png

As you can see robohashes are hilariously brilliant and served from our static domain. The URL is actually rewritten:

<action type="Rewrite" url="gravatar.ashx?hash={R:2}&amp;size={R:1}" appendQueryString="false" />

And in the same web.config file we have the cache profiles:

<staticContent>
    <clientCache httpExpires="Sun, 29 Mar 2020 00:00:00 GMT" cacheControlMode="UseExpires" />
</staticContent>
<caching>
    <profiles>
        <add extension=".ashx" policy="CacheForTimePeriod"  kernelCachePolicy="DontCache" duration="01:00:00" />
        <add extension=".png" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" location="Any" />
        <add extension=".jpg" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" location="Any" />
        <add extension=".gif" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" location="Any" />
        <add extension=".ico" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" location="Any" />
    </profiles>
</caching>

For good measure in the gravatar.ashx file we also set a cache policy:

<%@ WebHandler Language="C#" Class="GravatarImage" %>

using System;
using System.Web;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Net;

public class GravatarImage : IHttpHandler {

    public void ProcessRequest (HttpContext context) {

        // Adds document content type        
        context.Response.Cache.SetCacheability(HttpCacheability.Public);
        context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(60));
        context.Response.Cache.SetMaxAge(new TimeSpan(1, 0, 0));
        context.Response.AddHeader("Last-Modified", DateTime.Now.ToLongDateString());

        // Get params and send initial request to gravatar
        string Hash = context.Request.QueryString["hash"];
        string Size = context.Request.QueryString["size"];
        string URL = "http://www.gravatar.com/avatar/" + Hash + "?r=pg&s=" + Size + "&d=404";

        // Make request to gravatar
        bool Fetched = makeAvatarRequest(URL);

        // Backup to robo hash
        if (!Fetched)
        {
            URL = "http://robohash.org/" + Hash + ".png?size=" + Size + "x" + Size + "&bgset=bg2";
            Fetched = makeAvatarRequest(URL);
        }

        // Fallback if gravatar doesn't match and robohash is down
        if (!Fetched)
        {

        }

        // Cache this handler response for 1 hour.
        HttpCachePolicy c = context.Response.Cache;
        c.SetCacheability(HttpCacheability.Public);
        c.SetMaxAge(new TimeSpan(1, 0, 0));
    }

    // Attempt a request for avatar
    private bool makeAvatarRequest(string URL)
    {        
        try
        {
            WebRequest request = WebRequest.Create(URL);
            using (WebResponse response = request.GetResponse())
            {
                using (Stream responseStream = response.GetResponseStream())
                {
                    displayImage(responseStream);
                    return true;
                }
            }
        }
        catch (WebException ex)
        {
            return false;
        }
    }

    // Display the image from stream
    private void displayImage(Stream stream)
    {
        HttpContext.Current.Response.ContentType = "image/png";
        Image img = Image.FromStream(stream);
        MemoryStream temp = new MemoryStream();
        img.Save(temp, ImageFormat.Png);
        byte[] buffer = temp.GetBuffer();
        HttpContext.Current.Response.OutputStream.Write(buffer, 0, buffer.Length);

        img.Dispose();
        temp.Dispose();        
    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

Note we use Response.cache AND CachePolicy at the bottom

When I use YSlow, every image on the page has a future expiry date, EXCEPT these avatars which have no expiry date. Every time a page is requested they are fetched again.

The idea of the script is to fetch the avatar from the external URL and cache it for 1 hour. It's then served from our website.

Can anyone help us out here? An example page with the avatars being used without cache is: http://www.scirra.com/forum/construct-in-ludum-dare-21_topic44523.html


回答1:


Because you are using a handler you need to handle the caching headers in your own code, ie returning the 304 repsonse as well. So check the dates on the headers against the files and return 304's where appropriate.

We have code similar to the following at the start of some our image handlers

var lastModified = this.LastModifiedFileTime(path);
var isNotModified = this.WriteConditional304(context, lastModified);
if (isNotModified)
    return;

the two methods used look roughly as below.

protected bool WriteConditional304(HttpContext context, DateTime lastWrite)
    {
        if (context.Request.Headers[since] != null || context.Request.Headers[eTag] != null)
        {
            try
            {
                DateTime date = context.Request.Headers[since] != null ? DateTime.Parse(context.Request.Headers[since]) : new DateTime(long.Parse(context.Request.Headers[eTag]));

                if (lastWrite <= date)
                {
                    Write304(context);
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        return false;
    }



protected DateTime LastModifiedFileTime(string path)
    {
        FileInfo fi = new FileInfo(path);
        var modificationTime = fi.LastWriteTime;
        // negates the smaller parts of the date as the header doesnt carry them
        var date = new DateTime(modificationTime.Year, modificationTime.Month, modificationTime.Day, modificationTime.Hour,
            modificationTime.Minute, modificationTime.Second);
        return date;
    }


来源:https://stackoverflow.com/questions/7410357/asp-net-ashx-handler-not-caching

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!