ASP.net ashx 处理程序不缓存

发布于 12-04 08:19 字数 4529 浏览 0 评论 0 原文

我们最近安装了 Robohash 作为 Gravatar 的绝佳后备:

在此处输入图像描述

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

如您所见,robohashes 非常出色,并且由我们的静态域提供服务。 URL 实际上被重写了:

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

在同一个 web.config 文件中,我们有缓存配置文件:

<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>

为了在 gravatar.ashx 文件中进行良好的测量,我们还设置了缓存策略:

<%@ 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;
        }
    }

}

请注意,我们在底部使用 Response.cache 和 CachePolicy

当我使用 YSlow 时,页面上的每个图像都有一个未来的到期日期,除了这些没有到期日期的头像。每次请求页面时,都会再次获取它们。

该脚本的想法是从外部 URL 获取头像并缓存 1 小时。然后从我们的网站提供。

有人可以帮助我们吗?在没有缓存的情况下使用头像的示例页面是: http://www.scirra.com/forum/construct- in-ludum-dare-21_topic44523.html

We recently installed Robohash as a great fallback for Gravatar:

enter image description here

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}&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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

書生途 2024-12-11 08:19:42

因为您使用的是处理程序,所以您需要在自己的代码中处理缓存标头,即也返回 304 响应。因此,请根据文件检查标题上的日期,并在适当的情况下返回 304。

我们在一些图像处理程序的开头有类似于以下的代码,

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

所使用的两种方法大致如下所示。

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;
    }

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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文