4

編集済み

クライアントに画像をキャッシュしたいのですが、mvc 3でそれを行うにはさまざまな方法があることを知っています(間違っている場合は修正してください)

1)httpヘッダーOutputCacheAttributeの助けを借りて動作するものを使用できます。ただし、時間が経過しない限り(画像が変更された場合でも)Expires戻ります。304 Not Modified

2)古い画像が表示されないようにするにはLast-Modifiedhttpヘッダー(を使用OutputCacheAttribute)を使用できます。この場合、ブラウザはIf-Modified-Sincehttpヘッダーを使用してサーバーにリクエストを送信します。サーバー上でオブジェクトがまだ有効かどうかを確認し、有効かどうかを確認しますLast-Modified。httpヘッダーを返すだけです(ブラウザはローカルキャッシュから画像を取得します)。オブジェクトが変更された場合200 OKステータスとともに返します。
そのため、ブラウザは、自身のキャッシュから画像を取得する前に、毎回サーバーにリクエストを送信する必要があります。これが例です-

3)別の方法があります(私の場合は正しい方法で言われたので、画像がほとんど変更されないためです...とにかく、これを正確に実装する必要があります):変更された日付を画像のURLに追加し、次のようにキャッシュを設定しますExpires永遠に(1年以上)。画像が変更された場合新しいバージョンの新しいURLを送信する必要があります。

コードは次のとおりです。

public class LastModifiedCacheAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is FilePathResult)
        {
            var result = (FilePathResult)filterContext.Result;
            var lastModify = File.GetLastWriteTime(result.FileName);
            if (!HasModification(filterContext.RequestContext, lastModify))
                filterContext.Result = NotModified(filterContext.RequestContext, lastModify);
            SetLastModifiedDate(filterContext.RequestContext, lastModify);
        }
        base.OnActionExecuted(filterContext);
    }

    private static void SetLastModifiedDate(RequestContext requestContext, DateTime modificationDate)
    {
        requestContext.HttpContext.Response.Cache.SetLastModified(modificationDate);
    }

    private static bool HasModification(RequestContext context, DateTime modificationDate)
    {
        var headerValue = context.HttpContext.Request.Headers["If-Modified-Since"];
        if (headerValue == null)
            return true;
        var modifiedSince = DateTime.Parse(headerValue).ToLocalTime();
        return modifiedSince < modificationDate;
    }

    private static ActionResult NotModified(RequestContext response, DateTime lastModificationDate)
    {
        response.HttpContext.Response.Cache.SetLastModified(lastModificationDate);
        return new HttpStatusCodeResult(304, "Page has not been modified");
    }
}

そしてLastModifiedCacheAttribute、Global.asaxに登録し、次のOutputCacheAttributeをアクションメソッドに適用しました。

[HttpGet, OutputCache(Duration = 3600, Location = OutputCacheLocation.Client, VaryByParam = "productId")]
public FilePathResult GetImage(int productId)
{ // some code }

上記のコードを使用すると、ブラウザはサーバーにリクエストを送信せず、代わりに、期間が終了しない限り、キャッシュから画像を取得するように見えます。(画像を変更すると、ブラウザに新しいバージョンが表示されません)

質問:

1) 3番目のアプローチを実装して、画像が変更されない限り、ブラウザがクライアントキャッシュから画像を取得する(そして、画像が必要になるたびにサーバーに応答を送信しない)ようにするにはどうすればよいですか?
編集済み:実際のコードを高く評価します。

2)上記のコードでは、最初の画像リクエストの時刻がLast-Modifiedに書き込まれます(理由はわかりません)。ファイルの変更日をLast-Modifiedに書き込む方法は?
編集:この質問は2番目のアプローチに関連しています。また、クライアントのみにキャッシュしてLast-Modified実装を使用すると304 Not Modified、を押した場合にのみステータスが取得されますF5。同じURLを再入力すると、が取得されます200 OK。使用せずにクライアントにキャッシュすると、何があっLast-Modifiedても常に返されます。200 OKこれはどのように説明できますか?

4

4 に答える 4

1

ETag ( http://en.wikipedia.org/wiki/HTTP_ETag ) の使用を調べることができます。それが、あなたの質問を読んで最初に考えたことです。

こちらもご覧ください: Set ETag for FileResult - MVC 3

于 2013-02-25T23:54:45.677 に答える
0

VaryByCustom オプションを出力キャッシュで使用すると、カスタム属性を使用せずにこれを実現できます。メソッド コードを次のように変更します。

[HttpGet, OutputCache(Duration = 3600, 
    Location = OutputCacheLocation.Client, 
    VaryByCustom = "imagedate")]
public FilePathResult GetImage(int productId)
{ // some code }

次に、次のコードを Global.asax に追加します。

    public override string GetVaryByCustomString(System.Web.HttpContext context, string custom)
    {
        if (custom.ToLower() == "imagedate")
        {
            return System.IO.File.GetLastWriteTime(Server.MapPath("~/Images/my-image.png")).ToString();
        }
        else
        {
            return base.GetVaryByCustomString(context, custom);
        }
    }

画像ファイルのタイムスタンプが変更されると、GetVaryByCustomString メソッドの戻り値が変更され、キャッシュされた値を使用するのではなく、ASP.NET が画像を再読み込みします。

詳細については、 http://msdn.microsoft.com/en-us/library/aa478965.aspxを参照してください。

于 2013-02-25T17:08:55.083 に答える
0

私が正しく理解していれば、あなたが求めているのは無限のキャッシングであり、リソースの実際の URL を変更してキャッシュを無効にすることに依存しています。

その場合、実際の実装ははるかに簡単で、ヘッダーを手動で処理する必要はないと思います。

最終的には、次のような URL で画像をロードできるようにすることがポイントです。

http://someDomain/product/image/1?v={something}

「1」はproductIdであり、ある種のバージョン識別子 (「v」) を指定します。

重要なのは、その URL を作成することです。ここで、vの値は、画像の最後の変更に依存します (おそらく、画像または製品と共に保存する必要があります)。おそらく変更日をハッシュして、それを使用できます。

次に URL を作成するときに、最終変更日が同じであれば、同じハッシュ値が得られるため、以前と同じ URL がレンダリングされ、ブラウザはサーバーに何も要求せずにキャッシュからそれをロードします。 .

画像が更新され、その変更日が変更されるとすぐに、コードは別の URL を生成し、ブラウザーに再度要求させることになります。

次にOutputCache、クライアントにキャッシュするように構成されたアクションに属性を適用するだけで ( を指定する必要はありませんVaryByParam)、設定する必要があります。

于 2013-02-18T21:24:01.257 に答える
0

最初はこの回答を使用しましたが、何らかの理由で画像が変更されたときにクライアントで更新されず、代わりにキャッシュされたバージョンの画像が表示されます。

したがって、ソリューションは3番目のオプションであるバージョン管理を使用しています。製品画像データベースからLastUpdated日時フィールドを追加するだけです

アクション方法

    [HttpGet]
    [OutputCache(
    Duration = 7200,
    VaryByParam = "productId;lastUpdated",
    Location = OutputCacheLocation.Client)]
    public ActionResult GetImage(string productId, string lastUpdated)
    {
        var dir = Server.MapPath("~/productimages/");
        var path = Path.Combine(dir, productId + ".jpg");
        return base.File(path, "image/jpeg");
    }

ビューで

<img src="@Url.Action("GetImage", "Home", new { productId = "test-product-100", 
lastUpdated =Model.LastUpdated })" />

この投稿から取られたアイデア。

回答が遅くなりましたが、希望は誰かを助けます。

于 2016-03-26T16:00:10.993 に答える