在IIS7上使用MVC3将图片放置在CDN上

8

我需要在我的网站上为所有图片使用CDN。因此,我决定使用IIS Url重写模块,因为手动编辑所有网站视图是不可能的。

因此,我已经为IIS制定了规则,例如:

<rule name="cdn1" stopProcessing="true">

   <match url="^Content/Images.*/(.*\.(png|jpeg|jpg|gif))$" />

   <action 
      type="Redirect" 
      url="http://c200001.r9.cf1.rackcdn.com/{ToLower:{R:1}}" 
      redirectType="Permanent" />

</rule>

这个方案是可行的,但是你可以看到使用了重定向类型(301永久重定向)。我认为它会影响网站性能。也许可以编辑Request.Output来替换图像URL?

请建议如何在不编辑视图和避免重定向的情况下使用CDN来处理图像问题?

任何帮助都将不胜感激。

2个回答

7

我同意Steve的观点。你使用URL重写器进行301重定向,但是对于页面所需的每个图像,浏览器仍然首先向服务器发出请求,以发现它被301重定向到CDN Url。此时你只能节省下载内容。

相反,你可以设置一个响应过滤器,在将响应发送到客户端浏览器之前修改资产的URL。这样,客户端浏览器就不必为静态资源向您的服务器发出任何调用:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    filterContext.RequestContext.HttpContext.Response.Filter = new CdnResponseFilter(filterContext.RequestContext.HttpContext.Response.Filter);
}

接下来是CdnResponseFilter:

public class CdnResponseFilter : MemoryStream
{
    private Stream Stream { get; set; }

    public CdnResponseFilter(Stream stream)
    {
        Stream = stream;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        var data = new byte[count];
        Buffer.BlockCopy(buffer, offset, data, 0, count);
        string html = Encoding.Default.GetString(buffer);

        html = Regex.Replace(html, "src=\"/Content/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);
        html = Regex.Replace(html, "href=\"/Content/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);              

        byte[] outData = Encoding.Default.GetBytes(html);
        Stream.Write(outData, 0, outData.GetLength(0));
    }

    private static string FixUrl(Match match)
    {
        //However the Url should be replaced
    }
}

这将导致所有类似于 <img src="\Content\whatever.jpg" /> 的内容资产都会被转换为 <img src="cdn-url.com\Content\whatever.jpg" />

我可以问一下,在ASP MVC应用程序中我们应该把这个响应过滤器放在哪里? - DevMania
实际的响应过滤器类?该类可以位于项目中的任何位置,只要控制器可以访问该类即可。 - Mike Richards
谢谢您,我的意思是如何在 ASP MVC 中使用它,应该在哪里注入? - DevMania
OnActionExecuted方法可以在控制器类中重写。上面答案中的第一个代码片段展示了你在哪里注入过滤器。 - Mike Richards
考虑使用这一行代码替换2个正则表达式。它更加健壮。html = Regex.Replace(html, "([href|src]=["'])(/Content/[^"']+)", "$1" + GetCdnEndPoint() + "$2", RegexOptions.IgnoreCase); - DJA

1

考虑到原始URL来自您的内容而不是书签,我认为您将难以避免向您的站点发出请求和重定向;这可能会对性能产生重大影响,从而抵消使用CDN的好处。

如果您可以在传输到浏览器的HTML上应用URL重写,而不是在请求进入时进行重写,那就更好了。

问题是,我不知道如何做(除非您正在使用ISA服务器,在这种情况下我可以告诉您,但我怀疑您没有)!

您可以创建一个自定义ActionFilter并覆盖OnResultExecuted,但需要使用过滤器属性注释控制器。


关于OnResultExecuted:是否可以编辑输出的HTML?我无法弄清楚,谷歌也不想帮助我。 - frm
@Mike知道我在找什么 - 我们需要的是ASP.NET响应过滤器,而不是MVC的... - Steve Morgan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接