前言

要发布网站需要做一些优化, 比如 cache, compression, minification 等等.

以前有写过相关的文章: Asp.net core 学习笔记 ( IIS, static file 性能优化 )

这篇作为一个大整理.

Publish Website

Visual Studio 我就不介绍了. 这里用的是 dotnet CLI

dotnet publish ProjectName.csproj -o C:\keatkeat\projects\release

project name 是 optional, -o 是 output 路径

注: 它不会把原先的 files delete 掉哦, 而且也没有 delete existing files 的 command. Github Issue,

Compression

压缩就是把 .js, .css 这类 files 做成 gzip 或者 br, 这可以大大介绍文件体积, 传输的时候就快多了.

在 service provider 做 setup, EnableForHttps 默认是 false, 开启的话要注意 security risk.

builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
});

接着在 UseStaticFiles 之前运行 UseResponseCompression

app.UseResponseCompression();
app.UseStaticFiles();

效果

注: Razor page / MVC view 返回的 HTML response 也是会被 compress 的哦

Cache

在 service provider 设置

builder.Services.Configure<StaticFileOptions>(options =>
{
options.OnPrepareResponse = ctx =>
{
var cachePeriod = TimeSpan.FromDays(365 * 15).TotalSeconds.ToString();
ctx.Context.Response.Headers.Append("Cache-Control", $"public, max-age={cachePeriod}");
};
});

效果

游览器是依据 URL 做 cache 的, 像 .js .css file name 最好配上 hash, 只要内容不变缓存就一定生效, 只要内容变了 hash 也就变了, 缓存自然就无效了. 具体做法可以看这篇

缓存是 static file 而已, Razor Page response 的 HTML 是不可能被缓存的哦 (那个要缓存就要做 service worker 了)

注意: 用 chrome 测试的话, dev tools 开启会自动缓存哦, 所以要测试最好是把 dev tools 关了. 参考: stackoverflow – Google chrome css doesn't update unless clear cache

Minification

minification 就是把空格, 注释删除, 把方法变量名字变短. .js .css 我都是用 webpack 做, 可以看这篇.

Razor Page response 的 HTML 则需要用到插件 WebMarkupMin

它有多个版本, 要找对来安装哦, 每一个是不同 package 来的...

也没有找到教程, 101 篇是 2016 年写的 HTML minification using WebMarkupMin in ASP.NET Core

在 service provider 设置

builder.Services.AddWebMarkupMin(options =>
{
options.AllowMinificationInDevelopmentEnvironment = true;
}).AddHtmlMinification();

如果想在 dev mode 看到效果要记得开启 AllowMinificationInDevelopmentEnvironment 哦

接着在 RazorPages 之前 UseWebMarkupMin

app.UseWebMarkupMin();
app.MapRazorPages();

当遇上 \r\n new line and white-space: pre-line

默认情况下, minification 也会把 \r\n new line 给删除掉, 当我们需要 \r\n 的时候可以用以下 2 格方法

1. wmm:ignore

<!--wmm:ignore-->@Html.Raw("Test \nTest")<!--/wmm:ignore-->

2. 修改 default setting

services.AddWebMarkupMin().AddHtmlMinification(options =>
{
options.MinificationSettings.PreserveNewLines = true;
});

这样 \r\n 就被保留了

隐患和坑

1. 之前做 service worker 的时候有遇过一些鬼问题 Github Issus – Service Worker: Hash Mismatch

2. WhatsApp share link image no show.

这是因为 HTML minify 以后 quote 会消失. 而 WhatsApp 的 crawl 视乎不够聪明. 参考1, 参考2 (sharing debugger 是 ok 的, facebook messager 也是 ok 的, 就 WhatsApp 有问题....)

解决方法是保留 quote

services.AddWebMarkupMin().AddHtmlMinification(options =>
{
options.MinificationSettings.AttributeQuotesRemovalMode = WebMarkupMin.Core.HtmlAttributeQuotesRemovalMode.KeepQuotes;
});

HSTS

HSTS 是告诉游览器这个网站只允许 HTTPS 访问, 即使 certificate 过期了, 用户也无法 by pass. (第一次访问允许 http, 游览器得知后就不允许了, 还有一种极端的做法是 manual submit to 游览器公司, 那么连第一次都必须是 HTTPS)

最大的好处是绝对安全, 另一个是游览器会强制使用 HTTPS 访问也少了 http redirect to https 的问题 (性能慢)

ASP.NET Core 默认的 template 就有设置好这个了.

可以自定义时间, 默认是 30 days. (也就是说 30 days 内, 用户只能 HTTPS 访问)

builder.Services.Configure<HstsOptions>(options =>
{
options.MaxAge = TimeSpan.FromMinutes(1); // 默认是 30days
});

接着放到最上方 (比 ExceptionHandler 底而已), 请求一进来就处理.

var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}

URL Rewrite HTTPS and WWW

用户不习惯写 HTTPS and WWW 所以需要做 redirect 统一它们. 不然统计很乱.

service provider 设置 (如果项目是放到 subdomain, 拿自然就没有 redirect WWW 了哦)

builder.Services.Configure<RewriteOptions>(options =>
{
options.AddRedirectToHttpsPermanent();
options.AddRedirectToWwwPermanent();
// options.AddRedirectToHttps();
// options.AddRedirectToWww();
});

permanent 是 301, 没有 permanent 是 302 (temporary 的意思)

接着

var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseRewriter();
// app.UseHttpsRedirection();
app.UseResponseCompression();

在 UseHsts 之后执行 UseRewriter

注意: 上面把默认 template 的 UseHttpsRedirection 注释掉了, 其实它和 AddRedirectToHttpsPermanent 功能是一样的.

可以选任意其中一个来用, 我这里统一让 Rewriter 负责. 参考: HTTPS Redirection Middleware alternative approach

301 Redirect for SEO

301 redirect 也是网站发布需要考虑到的. 它也是通过 Rewriter 完成的.

builder.Services.Configure<RewriteOptions>(options =>
{
options.AddRedirect(@"(zh-Hans|id|cn)\/(.*)", "/$2", (int)HttpStatusCode.Moved);
options.AddRedirect(@"(zh-Hans|id|cn)", "/", (int)HttpStatusCode.Moved);
options.AddRedirect(@"blogs\/(.*)", "/tourist-attractions/$1", (int)HttpStatusCode.Moved);
options.AddRedirect(@"blogs", "/tourist-attractions", (int)HttpStatusCode.Moved);
options.AddRedirect(@"about-us", "/about", (int)HttpStatusCode.Moved);
options.AddRedirect(@"cars\/.*", "/fleets", (int)HttpStatusCode.Moved);
options.AddRedirect(@"packages", "/pricing", (int)HttpStatusCode.Moved);
options.AddRedirect(@"testimonials", "/reviews", (int)HttpStatusCode.Moved);
});

第一个参数是 match regex, 第二个是 redirect to 可以使用 $1 配合 regex

308 或 301 都是正确的, 暂时修改地址的话就时候 302

提醒:

Close IIS Feature

上面介绍的许多功能, IIS 都有自带的. 要确保不要跑 2 轮, 必须把 IIS 相关功能移除.

web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<!-- for debug -->
<aspNetCore processPath="dotnet" arguments=".\TestMiniCompressCacheHttpsWww.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
<!-- <aspNetCore processPath="dotnet" arguments=".\TestMiniCompressCacheHttpsWww.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" /> -->
<modules>
<remove name="RewriteModule" />
<remove name="AspNetCoreModule" />
<!-- <remove name="RequestFilteringModule" /> -->
<remove name="iisnode" />
<!-- <remove name="ProtocolSupportModule" /> -->
<!-- <remove name="IsapiModule" /> -->
<remove name="IpRestrictionModule" />
<!-- <remove name="IsapiFilterModule" /> -->
<remove name="HttpRedirectionModule" />
<remove name="DynamicIpRestrictionModule" />
<!-- <remove name="DirectoryListingModule" /> -->
<!-- <remove name="DefaultDocumentModule" /> -->
<remove name="CorsModule" />
<!-- <remove name="ConfigurationValidationModule" /> -->
<remove name="ApplicationInitializationModule" />
<remove name="WebSocketModule" />
<remove name="AnonymousIdentification" />
<remove name="DefaultAuthentication" />
<remove name="FileAuthorization" />
<remove name="FormsAuthentication" />
<remove name="Profile" />
<remove name="OutputCache" />
<remove name="UrlAuthorization" />
<remove name="RoleManager" />
<remove name="ScriptModule-4.0" />
<remove name="UrlMappingsModule" />
<remove name="UrlRoutingModule-4.0" />
<remove name="WindowsAuthentication" />
<remove name="Session" />
<!-- <remove name="StaticFileModule" /> -->
<!-- <remove name="StaticCompressionModule" /> -->
</modules>
<!-- for debug -->
<!--<httpErrors errorMode="Detailed" />-->
<httpErrors errorMode="DetailedLocalOnly" />
</system.webServer>
</location>
</configuration>

Folder & File Permission

IIS 的 Application 要读写 File 是需要额外 permission 的。

不够 permission 就会报错 Access to the path。

举个例子

var tempFolder = Path.Combine(env.WebRootPath, "uploaded-files");
var bytes = Encoding.UTF8.GetBytes("Hello World");
await System.IO.File.WriteAllBytesAsync($@"{tempFolder}\test.txt", bytes);

如果 test 不存在,或许你可以成功创建它,但是如果 test 已存在,它需要 override,这个可能就会报错 permission 了。

我一般上会直接把 wwwroot folder 添加所以权限给 IIS_IUSRS

wwwroot folder > right click > Properties > Security > Edit > Add > IIS_IUSRS > OK > tick Full control >  Apply > OK

ASP.NET Core – 网站发布要做的事儿 Publish, Minification, Compression, Cache, HSTS, URL Rewrite Https & www, Close IIS Feature的更多相关文章

  1. ASP.NET Core 网站发布到Linux服务器(转)

    出处;ASP.NET Core 网站发布到Linux服务器 长期以来,使用.NET开发的应用只能运行在Windows平台上面,而目前国内蓬勃发展的互联网公司由于成本的考虑,大量使用免费的Linux平台 ...

  2. ASP.NET Core 网站发布到Linux服务器

    长期以来,使用.NET开发的应用只能运行在Windows平台上面,而目前国内蓬勃发展的互联网公司由于成本的考虑,大量使用免费的Linux平台,这就使得.NET空有一身绝技但无法得到广大的施展空间,.N ...

  3. ASP.NET Core 网站在Docker中运行

    Docker作为新一代的虚拟化方式,未来肯定会得到广泛的应用,传统虚拟机的部署方式要保证开发环境.测试环境.UAT环境.生产环境的依赖一致性,需要大量的运维人力,使用Docker我们可以实现一次部署, ...

  4. docker 初识之二(简单发布ASP.NET Core 网站)

    在发布ASP.NET Core网站以前,先介绍一下DaoCloud 一个免费的docker云容器服务平台.登陆官方网站,创建一台docker主机,这台主机有120分钟的使用时间,对于鄙人学习使用正好合 ...

  5. .Net Core 3 骚操作 之 用 Windows 桌面应用开发 Asp.Net Core 网站

    前言 曾经在开发 Asp.Net 网站时就在想,为什么一定要把网站挂到 IIS 上?网站项目的 Main 函数哪儿去了?后来才知道这个 Main 函数在 w3wp.exe 里,这也是 IIS 的主进程 ...

  6. Windows平台部署 Asp.Net Core 3.1.0,将 ASP.NET Core 应用发布到 IIS ,使用 IIS 在 Windows 上托管 ASP.NET Core

    第一部分:本教程介绍如何在 IIS 服务器上托管 ASP.NET Core 应用. 官方文档地址:https://docs.microsoft.com/zh-cn/aspnet/core/tutori ...

  7. 将asp.net core站点发布到IIS上遇到的问题

    今天第一次将整个 asp.net core 站点发布到 IIS 上,以前都是发布到 Linux 服务器上. 开始使用 dotnet publish -c release 命令发布,用浏览器访问站点时出 ...

  8. ASP.NET CORE网站部署到 windows server 的IIS 上去

    章基于我自己经验的一个总结,在windows服务器上部署asp.net core网站.环境是 windows server 2012数据中心版本 第一步先安装 IIS 服务器 接下来就是一路下一步,然 ...

  9. asp.net core 使用 TestServer 来做集成测试

    asp.net core 使用 TestServer 来做集成测试 Intro 之前我的项目里的集成测试是随机一个端口,每次都真实的启动一个 WebServer,之前也有看到过微软文档上 TestSe ...

  10. ASP.NET Core下发布网站

    一.windows下发布到IIS 1.前奏:IIS上的准备 (1)IIS 必须安装AspNetCoreModule 模块 下载地址:(DotNetCore.2.0.3-WindowsHosting-a ...

随机推荐

  1. nacos启动失败:No DataSource set

    通过docker查看nacos的日志发现nacos好端端的突然不能用了 docker logs nacos 报错后说是no datasource set,我看了我在docker里的MySQL是正常启动 ...

  2. Scratch作品-巴黎2024奥运会

    ​ <Scratch作品-巴黎2024奥运会>是一款以巴黎2024年奥运会为主题的互动作品,专为儿童和青少年设计.通过Scratch编程语言,这个作品生动地再现了奥运会的精彩瞬间,结合了动 ...

  3. matplotlib中渐变颜色条转CSS样式(hex格式)——同mapbox中cog的颜色条拉伸显示

    matplotlib中渐变颜色条转CSS样式(hex格式)--同mapbox中cog的颜色条拉伸显示 应用场景: 1.适用于mapbox中显示cog影像时,colormap_name拉伸颜色条转换 2 ...

  4. 【转载】 EdgeX Foundry试运行

    原文地址: https://www.cnblogs.com/charlieroro/p/14843335.html ========================================== ...

  5. MindSpore 计算框架 模型参数 和 优化器 参数的重新载入

    本文主要内容源于: https://www.mindspore.cn/tutorial/training/zh-CN/master/use/load_model_for_inference_and_t ...

  6. tf.py_func的一些使用笔记——TensorFlow1.x

    tensorflow.py_func是TensorFlow1.x版本下的函数,在TensorFlow.2.x已经不建议使用了,但是依然可以通过tf.compat.v1.py_func的方式来进行调用. ...

  7. 哈希基础知识学习-python版

    哈希 哈希表 根据key直接进行访问的无序数据结构,复杂度为O(1) 哈希表的实现---字典 初始化 d1 = dict() 查找 #使用中括号[]进行查找,括号内为特定的键, 键-值 dic = { ...

  8. 【Playwright+Python】系列教程(八)鉴权Authentication的使用

    写在前面 还是有些絮叨的感觉,官方翻译和某些博主写那个玩楞,基本都是软件直接翻译后的产物. 读起来生硬不说,甚至有的时候不到是什么意思,真的是实在不敢恭维. 到底是什么意思? 就是你已经登陆过一次,在 ...

  9. [SHOI2009] 会场预约 题解

    LG2161 显然: 任意时刻每个点最多被一条线段覆盖 暴力删每条线段的复杂度是对的 插入 \([l,r]\) 时需要删除的线段要么被 \([l,r]\) 包含,要么覆盖 \(l\) 或 \(r\) ...

  10. 从0实现基于Linux socket聊天室-实现聊天室的登录、注册功能-3

    上一篇我们已经讲了如何搭建一个多线程的服务器模型,可以支持多个客户端同时连接服务器,本篇我们来实现多个客户端,如何实现向服务器注册信息,并实现登录的功能. 数据结构 接着上一篇的实例代码继续增加功能. ...