gpt4 book ai didi

javascript - 对外部生成的静态内容进行指纹识别(ASP.NET + browserify)

转载 作者:数据小太阳 更新时间:2023-10-29 03:57:49 27 4
gpt4 key购买 nike

Node browserify在构建模块化 js 应用程序时非常棒。如果 gulp 也是设置的一部分,工作流 is further enhanced管理和解决依赖关系,适本地捆绑,使用 sourcemaps 进行 uglify,auto-polyfill,jshint,测试...这对于 css 以及预处理,自动前缀,linting,嵌入非常方便资源和生成文档。

TL;DR:通过 npm/bower,您可以访问广泛的前端库生态系统,使 nodejs 非常适合构建(不一定是服务!)客户端代码。事实上,将它用于客户端代码非常棒,npmbowergrunt/gulp 将在 VS 2015 中开箱即用。与此同时,我们设置了一个 gulp 任务来运行预构建并编写 dist js/css(捆绑输出)。

使用指纹 url 引用外部静态内容的好方法是什么?从长远来看,理想情况下,我们能够完全分离客户端内容,这样它就可以独立构建并部署到 CDN,而无需还必须构建应用程序的其余部分。

最佳答案

CSS 问题

由于 CSS 引用图像的相对 url,这些 url 也可能会发生变化,因此您需要在启动应用程序之前计算大量哈希计算,这会减慢签名 url 的生成速度。事实证明,编写代码来跟踪上次修改日期不适用于 CSS 图像 url。因此,如果 css 中引用的任何图像发生更改,则 css 也必须更改。

像 jquery-1.11.1.js 这样的独立文件版本控制问题

首先它破坏了源代码版本控制,Git 或任何版本控制会将 app-script-1.11.js 和 app-script-1.12.js 识别为两个不同的文件,将难以维护历史。

对于 jquery,它会在构建库时正常工作,并且大多数情况下您不会在页面上包含资源时更改它,但是在构建应用程序时,我们将有许多 JavaScript 文件并且更改版本将需要更改每个页面,但是,单个包含文件可能会做到这一点,但要考虑大量的 css 和大量图像。

将上次更新日期缓存为 URL 前缀

所以我们不得不想出像/cached/lastupdate/这样的静态内容的版本控制,这只不过是静态 Assets 的url前缀。 lastupdate 只是请求文件的最后更新日期时间。如果文件在应用程序范围内被修改,还有一个观察器会刷新缓存键。

最简单的方法之一是在 URL 中使用版本 key 。

在应用设置中定义版本如下

 <appSettings>
<add key="CDNHost" value="cdn1111.cloudfront.net"/>
</appSettings>

// Route configuration

// set CDN if you have
string cdnHost = WebConfigrationManager.AppSettings["CDNHost"];
if(!string.IsEmpty(cdnHost)){
CachedRoute.CDNHost = cdnHost;
}

// get assembly build information
string version = typeof(RouteConfig).Assembly.GetName().Version.ToString();

CachedRoute.CORSOrigins = "*";
CachedRoute.Register(routes, TimeSpam.FromDays(30), version);

现在在每个页面上,引用您的静态内容,

 <script src="@CachedRoute.CachedUrl("/scripts/jquery-1.11.1.js")"></script>

在呈现时,您的页面将呈现为(无 CDN)

 <script src="/cached/2015-12-12-10-10-10-1111/scripts/jquery-1.11.1.js"></script>

以CDN为

 <script 
src="//cdn111.cloudfront.net/cached/2015-12-12-10-10-10-1111/scripts/jquery-1.11.1.js">
</script>

将版本放在 URL 路径而不是查询字符串中可以使 CDN 性能更好,因为查询字符串可以在 CDN 配置中忽略(通常是默认情况)。

CachedRoute 类来自 https://github.com/neurospeech/atoms-mvc.net/blob/master/src/Mvc/CachedRoute.cs

public class CachedRoute : HttpTaskAsyncHandler, IRouteHandler
{

private CachedRoute()
{
// only one per app..

}

private string Prefix { get; set; }

public static string Version { get; private set; }

private TimeSpan MaxAge { get; set; }

public static string CORSOrigins { get; set; }
//private static CachedRoute Instance;

public static void Register(
RouteCollection routes,
TimeSpan? maxAge = null,
string version = null)
{
CachedRoute sc = new CachedRoute();
sc.MaxAge = maxAge == null ? TimeSpan.FromDays(30) : maxAge.Value;

if (string.IsNullOrWhiteSpace(version))
{
version = WebConfigurationManager.AppSettings["Static-Content-Version"];
if (string.IsNullOrWhiteSpace(version))
{
version = Assembly.GetCallingAssembly().GetName().Version.ToString();
}
}

Version = version;

var route = new Route("cached/{version}/{*name}", sc);
route.Defaults = new RouteValueDictionary();
route.Defaults["version"] = "1";
routes.Add(route);
}

public override bool IsReusable
{
get
{
return true;
}
}

public static string CDNHost { get; set; }

public override bool IsReusable
{
get
{
return true;
}
}

public class CachedFileInfo
{

public string Version { get; set; }

public string FilePath { get; set; }

public CachedFileInfo(string path)
{
path = HttpContext.Current.Server.MapPath(path);

FilePath = path;

//Watch();

Update(null, null);
}

private void Watch()
{
System.IO.FileSystemWatcher fs = new FileSystemWatcher(FilePath);
fs.Changed += Update;
fs.Deleted += Update;
fs.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.FileName;
}

private void Update(object sender, FileSystemEventArgs e)
{
FileInfo f = new FileInfo(FilePath);
if (f.Exists)
{
Version = f.LastWriteTimeUtc.ToString("yyyy-MM-dd-hh-mm-ss-FFFF");
}
else
{
Version = "null";
}
}


}

private static ConcurrentDictionary<string, CachedFileInfo> CacheItems = new ConcurrentDictionary<string, CachedFileInfo>();

public static HtmlString CachedUrl(string p)
{
//if (!Enabled)
// return new HtmlString(p);
if (!p.StartsWith("/"))
throw new InvalidOperationException("Please provide full path starting with /");

string v = Version;

var cv = CacheItems.GetOrAdd(p, k => new CachedFileInfo(k));
v = cv.Version;

if (CDNHost != null)
{
return new HtmlString("//" + CDNHost + "/cached/" + v + p);
}
return new HtmlString("/cached/" + v + p);
}

public override async Task ProcessRequestAsync(HttpContext context)
{
var Response = context.Response;
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetMaxAge(MaxAge);
Response.Cache.SetExpires(DateTime.Now.Add(MaxAge));

if (CORSOrigins != null)
{
Response.Headers.Add("Access-Control-Allow-Origin", CORSOrigins);
}


string FilePath = context.Items["FilePath"] as string;

var file = new FileInfo(context.Server.MapPath("/" + FilePath));
if (!file.Exists)
{
throw new FileNotFoundException(file.FullName);
}

Response.ContentType = MimeMapping.GetMimeMapping(file.FullName);

using (var fs = file.OpenRead())
{
await fs.CopyToAsync(Response.OutputStream);
}
}

IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
//FilePath = requestContext.RouteData.GetRequiredString("name");
requestContext.HttpContext.Items["FilePath"] = requestContext.RouteData.GetRequiredString("name");
return (IHttpHandler)this;
}
}

使用文件修改时间而不是版本

    public static HtmlString CachedUrl(string p)
{
if (!p.StartsWith("/"))
throw new InvalidOperationException("Please provide full path starting with /");
var ft = (new System.IO.FileInfo(Server.MapPath(p)).LastModified;
return new HtmlString(cdnPrefix + "/cached/" + ft.Ticks + p);
}

这会保留基于上次修改的版本,但这会增加每次请求时对 System.IO.FileInfo 的调用,但是您可以创建另一个字典来缓存此信息并观察更改,但它是很多工作。

关于javascript - 对外部生成的静态内容进行指纹识别(ASP.NET + browserify),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29725764/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com