ASHX通用处理程序在页面刷新之前不会命中(使用F5或Refresh按钮)

时间:2014-03-31 09:54:00

标签: html asp.net ashx generic-handler

我编写了一个图像处理程序,它通过在满足某些条件时发送304来实现客户端缓存。为了访问不同的照片或登录的人自己的照片,我们将处理程序以下列方式放在不同的页面上。

<img src="EmployeePhoto.ashx" />
<img src="EmployeePhoto.ashx?self" />
<img src="EmployeePhoto.ashx?default" />

问题是,如果我在页面上缓存图像后第二次点击链接访问任何页面,它就不会命中处理程序(调试程序不会命中)。但是如果我用F5或刷新按钮刷新那个页面,那么它只会点击处理程序并显示我想要显示的内容。

只有当我尝试使用附加的另一个参数(例如“&amp; date =”+ CurrentDate)访问它时,它才会触及处理程序,但它会破坏缓存的目的。

<img src="EmployeePhoto.ashx?default&date=03/31/14 00:00:00" /> //or something like that

我知道代码没有任何问题,因为它在被击中时效果很好。无论如何这是代码。

public void ProcessRequest(HttpContext context)
{
    var isDefault = true;
    var textIfModifiedSince = context.Request.Headers["If-Modified-Since"];
    context.Response.ClearHeaders();
    context.Response.Cache.SetCacheability(HttpCacheability.Public);
    context.Response.Cache.SetExpires(DateTime.Now.AddMonths(6));
    try
    {
        var isOwn = false;
        var user = /*Gets logged in user instance from service*/;
        var employeeId = 0;
        if (context.Request.QueryString.Count > 0)
        {
            if(context.Request.QueryString[0] == "self")
            {
                if (user != null)
                {
                    employeeId = Convert.ToInt32(user.EmployeeId);
                    isOwn = true;
                }
            }
            else if (!int.TryParse(context.Request.QueryString[0], out employeeId))
                employeeId = 0;
        }
        else
        {
            if (user != null)
            {
                employeeId = Convert.ToInt32(user.EmployeeId);
                isOwn = true;
            }
        }


        if (user != null && employeeId != 0)
        {
            var employee = GetEmployee(employeeId);
            if (
                (!string.IsNullOrEmpty(textIfModifiedSince) && employee.Modify_Date == null) 
                || !string.IsNullOrEmpty(textIfModifiedSince) 
                && employee.Modify_Date != null 
                && employee.Modify_Date <= Convert.ToDateTime(textIfModifiedSince).AddMinutes(1))
            {
                isDefault = false;
                context.Response.Cache.SetLastModified(Convert.ToDateTime(textIfModifiedSince));
                context.Response.Status = "304 Not Modified";
                HttpContext.Current.ApplicationInstance.CompleteRequest();
                return;
            }
            if (
                employee != null 
                && !string.IsNullOrEmpty(employee.Picture) 
                && (isOwn || employee.LocationID != null) 
                && (isOwn || HasRequiredRoles))
            {
                var path = context.Server.MapPath("~//" + EmployeePhotoPath);
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
                var fileName = employee.Picture;
                var destinationPath =
                    context.Server.MapPath("~//" + EmployeePhotoPath).ToString(CultureInfo.InvariantCulture);
                if (File.Exists(destinationPath + fileName))
                {
                    isDefault = false;
                    context.Response.Cache.SetLastModified(employee.Modify_Date > DateTime.Now ? DateTime.Now : (employee.Modify_Date ?? DateTime.Now));
                    context.Response.ContentType = GetContentType(employee.Picture);
                    context.Response.WriteFile(EmployeePhotoPath + employee.Picture);
                    HttpContext.Current.ApplicationInstance.CompleteRequest();
                    return;
                }
                isDefault = false;
                DownloadFromSFTP(path, employee.Picture, user, employeeId.ToString(CultureInfo.InvariantCulture));
                context.Response.Cache.SetLastModified(employee.Modify_Date > DateTime.Now ? DateTime.Now : (employee.Modify_Date ?? DateTime.Now));
                context.Response.ContentType = GetContentType(employee.Picture);
                context.Response.WriteFile(EmployeePhotoPath + employee.Picture);
                HttpContext.Current.ApplicationInstance.CompleteRequest();
            }
        }
    }
    catch (Exception ex)
    {
        Log.Debug("Photo Handler Failed.", ex);
    }
    finally
    {
        if (isDefault)
        {
            if (!string.IsNullOrEmpty(textIfModifiedSince))
            {
                context.Response.Cache.SetLastModified(Convert.ToDateTime(textIfModifiedSince));
                context.Response.Status = "304 Not Modified";
                HttpContext.Current.ApplicationInstance.CompleteRequest();
            }
            context.Response.Cache.SetLastModified(DateTime.Now);
            context.Response.ContentType = GetContentType("images/avatar.gif");
            context.Response.WriteFile("images/avatar.gif");
            HttpContext.Current.ApplicationInstance.CompleteRequest();
        }
    }
}

此外: 在以下情况中会出现此问题。

  1. 用户通过访问EmployeePhoto.ashx?Eid = 20349
  2. 来访问图像
  3. 管理员更改了Eid = 20349
  4. 的照片
  5. 用户再次访问该页面(不刷新,但从某个链接访问该页面)
  6. 页面上的缓存图像带来旧图像,如果它已经命中处理程序,那么情况已经在那里处理,但它没有,页面显示缓存版本本身。我只在镀铬上检查过它。

1 个答案:

答案 0 :(得分:1)

用法本身是错误的。

您想要来自同一网址的记录人物的独特图片吗?这是不可能的

点击网址后,浏览器会将其缓存。

我的解决方案是将用户ID附加到处理程序。

<img src="EmployeePhoto.ashx?uid=1" />
<img src="EmployeePhoto.ashx?self&uid=1" />
<img src="EmployeePhoto.ashx?default&uid=1" />

这样,broswer将发出请求并获得响应并将其缓存,并在网址匹配时为该特定用户使用缓存。

看到你的补充。我建议在数据库中存储一个标志,无论管理员是否更改了图像。然后,如果管理员更改了图片,那么您可以修改标题。现在,从db中删除标志,所以下次你不会这样做。