博客 (166)

前言:

ChatGPT 给了 3 条建议:

  1. 在应用程序中正确释放数据库连接。确保在使用完数据库连接后,将其关闭并将其返回到连接池中。您可以使用 using 语句来确保连接在使用完毕后被正确释放。

  2. 调整连接池的大小。默认情况下,连接池的最大大小为 100。如果您的应用程序需要更多的连接,则可以增加连接池的大小。您可以在连接字符串中设置 Max Pool Size 属性来调整连接池的大小。

  3. 调整连接池的超时时间。默认情况下,连接池中的连接在 30 秒钟内未使用时将被关闭。如果您的应用程序需要更长的连接时间,则可以增加连接池的超时时间。您可以在连接字符串中设置 Connection Lifetime 属性来调整连接池的超时时间。

亲测有效,尤其是第 3 条,原因是 Connection Lifetime 的默认值是 0,即没有超时限制。

—— 2023.5

一般地,我们使用 EF 连接数据库前会先初始化一个数据库上下文:

dbEntities db = new dbEntities();

虽然 ASP.NET 会在查询完毕后自动关闭该连接,但是在什么情况下回收等都是不确定的,所以会导致 MySQL 中出现很多 Sleep 的连接(执行命令 SHOW FULL PROCESSLIST 可见),占用数据库的连接数,除非主动调用 Dispose():

db.Dispose();

官方建议的写法是使用 using 语法:

using (dbEntities db = new dbEntities())
{
}

using 会自动调用 Dispose()。这样对减少连接数是很有效的,但官方提示为了提高下一次连接的速度,并不会完全关闭所有连接。

C# 8 建议写法:

using dbEntities db = new dbEntities();

在实际项目中(该项目有 500+处数据库连接)测试结果,在不执行 Dispose() 时稳定为 140 个左右连接数,使用 using 或 Dispose() 后稳定变为 40 个左右。


如果不小心在 using 外部或 Dispose() 后再次对该上下文执行查询操作会出现异常:

无法完成该操作,因为 DbContext 已释放。

此 ObjectContext 实例已释放,不可再用于需要连接的操作。

所以要避免出现这种情况。这里还有一种另类的解决方法(不建议),根据上下文的特性,只要在 using 内查询一次(譬如视图中需要用到的导航属性,即外键关联的表),就可以在外部使用这个属性。


(建议)在 ASP.NET MVC 或 Web API 项目中,如果一个控制器中仅在 Action 外部定义一个 DbContext,那么,只要重写该控制器的 Dispose() 方法即可:

private dbEntities db = new dbEntities();

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        db.Dispose();
    }
    base.Dispose(disposing);
}

上下文使用 private 修饰即可。


参考:SQL Server 连接池 (ADO.NET)

xoyozo 7 年前
7,347
变量名字段名
官方描述
return_code返回状态码

SUCCESS/FAIL

此字段是通信标识,非交易标识,交易是否成功需要查看 trade_state 来判断

在“统一下单”和“支付结果通知”中,该描述变成了:交易是否成功需要查看 result_code 来判断

result_code业务结果SUCCESS/FAIL
trade_state交易状态

SUCCESS — 支付成功

REFUND — 转入退款

NOTPAY — 未支付

CLOSED — 已关闭

REVOKED — 已撤销(付款码支付)

USERPAYING — 用户支付中(付款码支付)

PAYERROR — 支付失败(其他原因,如银行返回失败)

总的来说,

return_code 是用来判断通信状态的,个人理解在“结果通知”时必为 SUCCESS;

result_code 是用来判断业务结果的,指一次调用接口或回调的动作是否如愿执行成功。如“关闭订单”时关闭成功为 SUCCESS,因参数配置错误、找不到订单号、订单状态不允许关闭等其它关闭失败的情况为 FAIL;

trade_state 是用来判断交易状态的,“交易”是指微信支付订单。


另,在“统一下单”和“支付结果通知”中,return_code 的描述变成了:交易是否成功需要查看 result_code 来判断。不知道是官方笔误,还是真的可以用来判断交易是否成功,因为在调用“统一下单”时是未支付状态,根本没有支付成功的可能。


保险起见,我们在异步收到“结果通知”时,不要相信文档去判断 result_code,应调用“查询订单”,并判断 trade_state

xoyozo 7 年前
8,848

今天发现,阿里云 CDN 的 Refer 防盗链并没有真正防止白名单外的域名调用 OSS 的图片。经过一番研究发现,这跟 https 有关。

我在阿里云开通了 OSS 来存在图片,并使用 CDN 访问,在 CDN 中开启了 https,但并不强制。并且使用“白名单”的方式来设置 Refer 防盗链。关键是开启了“允许空 Referer”。

image.png 

我在 http://b.com/ 上测试调用 httphttps 的图片都是打不开的(防盗链有效),但是在 https://b.com/ 上却能显示 http 的图片(防盗链失效):

image.png

究其原因,是 https 页面在调用 http 图片时请求头不包含 Referer 字段,导致 CDN 判断 Referer 为空,这时候如果开启了为空也允许访问的话,就会出现防盗链失效的情况了。

image.png

image.png

总结:如果 CDN 开启了 https 访问,那么不要允许空 Referer。这里白名单内的网站必须使用与 CDN 一致的 protocol(http 或 https)。建议的写法是:

<img src="//cdn.xxx.com/abc.jpg" />


xoyozo 7 年前
9,961

这是一篇可能解决困扰了 .NET 程序猿多年的文章!

首先,使用 Visual Studio 2019 创建一个 ASP.NET WEB 应用程序,直接选用了 MVC 模板。

直接发布项目,默认的设置如下图:

image.png

对于小型项目,按默认设置发布基本可满足正常运行,首次运行打开第一个页面基本在 5~6 秒(视服务器配置),其它页面的首次打开也基本在 1~2 秒完成,非首次瞬间打开。

一旦项目功能变得复杂,文件增多,会导致发布后首次运行打开第一个页面 30 秒以上,其它页面的首次打开 10 秒左右,非首次瞬间打开。

这是因为项目在发布时没有进行预编译,而是在用户访问网页时动态编译,一旦应用程序池回收,或项目文件改动,都会重新编译,再次经历缓慢的“第一次”,这是不能忍的。

于是咱们来研究一下“预编译”。

在发布页面勾选“在发布期间预编译”,这时发布会在“输出”窗口显示正在执行编译命令(编译时间会比较长):

image.png

该选项对发布后的文件结构和内容影响不大,因此对首次执行效率的提升也不大,重要的在后面。

在“高级预编译设置”窗口中:

image.png

我们针对预编译选项和合并选项分别做测试。

不勾选“允许更新预编译站点”,会致 bin 目录中生成许多 .compiled 文件,而所有 .cshtml 文件的内容都是:

这是预编译工具生成的标记文件,不应删除!

如果是 Web From 网站,.aspx/.ashx 等文件内容同上。

尝试打开网站页面,你会发现,除了项目启动后的第一个页面仍然需要 1~2 秒(无 EF),其余每个页面的首次都是瞬间打开的(EF 的首次慢不在本文讨论范围)。这让我对预编译有一种相见恨晚的感觉!

这里偷偷地告诉你,把 Views 目录删掉也不影响网页正常打开哦~为什么不让删,咱也不敢问,咱也不敢删。

目的达到了,有一些后遗症需要解决,比如 bin 目录内杂乱无章。

选“不合并。为每个页面和控件创建单独的程序集”,结果是 bin 多出许多 App_Web_*.dll 文件。

选“将所有输出合并到单个程序集”,填写程序集名称。这时会发现“输出”窗口执行了命令:

image.png

如果程序集名称跟已有名称冲突,会发生错误:

合并程序集时出错: ILMerge.Merge: The target assembly '******' lists itself as an external reference.

查看 bin 目录,.compiled 文件还在,但 App_Web_*.dll 合并成了一个程序集。FTP 的“不合并”也是把所有 App_Web_*.dll 上传一遍,所以不存在相对于“合并”的增量发布优势。

是不是勾了“视为库组件删除(AppCode.compiled 文件)”.compiled 文件就会不见?意外之外,情理之中,bin 没有什么变化。

继续选择“将各个文件夹输出合并到其自己的程序集”,呃,bin 中文件数不降反增。

最后选择“将所有页和控件输出合并到单个程序集”,同样程序集名称不能冲突。结局令人失望,bin 中仍然一大堆 .compiled 和 App_Web_*.dll。


整理成表格:

1
允许更新预编译站点

aspnet_compiler.exe -v / -p \Source -u \TempBuildDir 

重复发布后 bin 目录文件数:不会增多(页面不进行预编译)

2

不允许更新预编译站点,不合并

aspnet_compiler.exe -v / -p \Source \TempBuildDir 

重复发布后 bin 目录文件数:.compiled 不会增多,App_Web_*.dll 增多

3

不允许更新预编译站点,不合并。为每个页面和控件创建单独的程序集

aspnet_compiler.exe -v / -p \Source -c -fixednames \TempBuildDir 

重复发布后 bin 目录文件数:不会增多(编译后的文件名固定,FTP 方式的部分 App_Web_*.dll 文件可能实现增量上传)

4

不允许更新预编译站点,将所有输出合并到单个程序集,不勾选“视为库组件”

aspnet_compiler.exe -v / -p \Source -c \TempBuildDir 

aspnet_merge.exe \TempBuildDir -o 程序集名称 -copyattrs AssemblyInfo.dll -a

重复发布后 bin 目录文件数:不会增多(.compiled 固定名称,App_Web_*.dll 合并为一个)

5

不允许更新预编译站点,将所有输出合并到单个程序集,勾选“视为库组件”

aspnet_compiler.exe -v / -p \Source \TempBuildDir 

aspnet_merge.exe \TempBuildDir -o 程序集名称 -copyattrs AssemblyInfo.dll -a -r 

重复发布后 bin 目录文件数:不会增多(.compiled 固定名称,App_Web_*.dll 合并为一个)

6

不允许更新预编译站点,将每个文件夹输出合并到其自己的程序集,前缀

aspnet_compiler.exe -v / -p \Source -c \TempBuildDir 

aspnet_merge.exe \TempBuildDir -prefix 前缀 -copyattrs AssemblyInfo.dll -a  

重复发布后 bin 目录文件数:.compiled 不会增多,App_Web_*.dll 增多

7

不允许更新预编译站点,将所有页和控件输出合并到单个程序集

aspnet_compiler.exe -v / -p \Source -c \TempBuildDir 

aspnet_merge.exe \TempBuildDir -w 程序集名称 -copyattrs AssemblyInfo.dll -a  

重复发布后 bin 目录文件数:.compiled 不会增多,App_Web_*.dll 增多

bin 目录下,页面的程序集文件(App_Web_*.dll)增多的原因是编译后的文件名不固定,发布到会导致残留许多无用的程序集文件。

相比较,如果第 3 种能实现 FTP 稳定的增量上传的话是比较完美的(还有一个缺点是:如果页面有删除,目标 bin 内对应该页面的 .compiled 和 .dll 不会删除,这跟“允许更新预编译站点”是一个情况),那么第 4 种 或第 5 种也是不错的选择(同样有缺点:执行合并比较慢)。

测试一个有 300 个页面的项目,compiler 用时约 2 分钟,merge 用时约 5 分钟,发布用时约 4 分钟。

这里有个槽点,执行预编译和合并是佛系的,CPU 和磁盘使用率永远保持在最低水平。

所以如果是要经常修改的项目,那么建议选择“不合并”的第 3 种发布方式:

微信图片_20190715160035.png

“视为库组件(删除 AppCode.compiled 文件)”:移除主代码程序集(App_Code 文件夹中的代码)的 .compiled 文件。 如果应用程序包含对主代码程序集的显式类型引用,则不要使用此选项。


补充:

  • 不允许更新预编译站点发布后,因为前端页面没有内容,因此无法单独修改发布(单独发布一个页面后,在访问时不会生效!),只能全站发布,耗时较长;bin 目录有变动将导致使用 InProc 方式存储的 Session 丢失。

  • 预编译的另一个优点是可以检查 .aspx / .cshtml 页面 C# 部分的错误(特别是命名空间和路径引用)。

  • 改为预编译发布后,可以将服务器上残留的 .master / .ascx / .asax 删除,但不能删除 .aspx / .ashx /.config 等。

  • VS 发布到 FTP 经常会遗漏一些页面文件,不合并时会遗漏独立文件,合并后也会遗漏合并后的 .dll 的文件,合并的好处就是方便检查是否完全上传发布。

  • 慎选“在发布前删除所有现有文件”!一旦勾选发布,世界就清静了,所有网友上传的图片附件以及网站运行产生的其它文件,消失得无影无踪。不管发布到文件系统还是发布到 FTP 都一样。当然,如果是先发布到文件系统,再通过 FileZilla 等 FTP 软件上传到服务器的,建议勾选此项。

  • .NET Core 应用程序部署:https://docs.microsoft.com/zh-cn/dotnet/core/deploying/index

  • 由于上传文件时 bin 目录文件较多,理论上 bin 目录内的文件有任何改动都会重启应用池,而且 VS 是单线程上传的,导致期间网站访问缓慢,服务器 CPU 升高,我的做法是:发布到文件系统,再使用专用 FTP 工具上传,上传用时约半分钟(如果大小不同或源文件较新则覆盖文件)。还嫌慢?那就打包上传,解压覆盖。

  • 关于本文研究对象的官方解释:高级预编译设置对话框

  • 出现“未能加载文件或程序集“***”或它的某一个依赖项。试图加载格式不正确的程序。”的问题时,先用改用 Debug 方式发布会报详细错误,一般是 .aspx 等客户端页面有 C# 语法问题,注意提示报错的是 /obj/ 目录下的克隆文件,应更改原文件。排除错误后关闭所有页面,再使用 Release 方式发布。

  • 2025年9月补充:因预编译发布后生成的文件时间都是系统最新时间,通过 FTP 上传到服务器时都会覆盖文件,可能导致杀毒软件进程 MsMpEng.exe 占用 CPU 过高。尝试选择不进行预编译,即取消“发布期间预编译”前的勾,这样发布的的文件时间都是文件本身的最后修改时间,重复发布不会更新这个时间,而且 bin 目录中也不会出现大量编译后的文件。这样通过 FTP 上传时只要设置“大小不同且文件较新则覆盖”就不会重复上传文件了,杀毒软件的工作量就能大大减少。缺点就是本文开头说的,每个页面的第一次打开会比较慢,而是非常慢。所以仍然需要勾选“发布期间预编译”,同时勾上“允许更新预编译站点”,这样 bin 目录中不会发现很多文件(合并不合并都一样),打开每个页面的第一次耗时也能在接受范围内。

xoyozo 7 年前
13,911

一般地,我们会设置网站中的图片文件仅允许本网站页面调用,或者开放地址栏直接打开,但不允许其它网站调用。

这就需要在 Web 服务器上判断图片的来源(Referer)。

但是,当网站页面是 https,而图片地址是 http 时,考虑到安全性,浏览器将不带 Referer,这时如果图片允许在地址栏直接打开(即 Referer 为空),就起不到防盗链的作用了。

所以图片服务器在处理防盗链时,尽量不要允许 Referer 为空时调用。这时如果要单独允许另一个网站来调用图片,应该使用一致的 protocol。

xoyozo 7 年前
4,850

第一种方式,直接执行上一页的原生方法:

var pages = getCurrentPages();
if (pages.length > 1) {
	var prePage = pages[pages.length - 2];
	prePage.onPullDownRefresh();
}

第二种方式,在上一页的 onShow() 中对数据进行更新。

推荐使用第一种方式,但只能调用原生方法,不能直接调用 methods 中的自定义方法(详见)。第二种方式的缺点是,有时候不需要在返回上一页时更新数据,但它仍会执行。

xoyozo 7 年前
3,077

2019/2/16 补充:参见 JavaScript 中的 TruthyFalsy

使用以下代码对字符串 s 进行判断:

var s = null;
if (s) {
    console.log('true');
} else {
    console.log('false');
}

测试当 s 为不同值时的结果如下:

s 的值if(s) 的结果
s = null;false
s = undefined;false
s = '';false
s = "";false
s = 0;false
s = 1;
true
s = 2;
true
s = -1;
true
s = '0';
true
s= ' ';true

结论:

s 未定义或未赋值时,结果为 false

s 为字符串类型时,长度为 0 即 false,长度大于 0 即 true

s 为数字类型时,等于 0 为 false,不等于 0 为 true


如果判断 s 的长度:

var s = null;
if (s.length > 0) {
    console.log('true');
} else {
    console.log('false');
}

那么会有以下结果:

s 的值if(s.length > 0) 的结果
s = null;Uncaught TypeError
s = undefined;Uncaught TypeError
s = '';false
s = "";false
s = 0;false
s = 1;
false
s = 2;
false
s = -1;
false
s = '0';
true
s= ' ';true

结论:

s 未定义或未赋值时,异常;

s 为字符串类型时,长度为 0 即 false,长度大于 0 即 true

s 为数字类型时,永远为 false

这样的话,if(s.length > 0) 等同于 if(s.length)


综上所述,判断一个字符串是否“有值且长度大于 0 ”,可以这样写:

var s = null;
if (s && s.length) {
    console.log('true');
} else {
    console.log('false');
}

相反,是否“无值或长度为 0”,可以这样写:

var s = null;
if (!s || !s.length) {
    console.log('true');
} else {
    console.log('false');
}

当然,如果要将不为 0 的数字类型也视为“有值”,只要 if(s) 或 if(!s) 即可。


xoyozo 7 年前
9,695

这是一个数据可视化项目,基于D3.js。能够将历史数据排名转化为动态柱状图图表。

先来看看效果:

https://xoyozo.net/Demo/BarGraph

作者 Jannchie 见齐还提供了官方视频教程:

https://www.bilibili.com/video/av28087807

不过由于开源项目的不断更新,该教程的部分内容已失效,本文针对 2018-12-25 版本总结了一些常用的配置说明,仅供参考。


从 GitHub 下载源代码,在 src 目录中可以看到 4 个文件:

bargraph.html --> 运行示例页面

config.js --> 配置文件

stylesheet.css --> 样式表

visual.js --> 核心文件


作者并没有将代码封装为插件的方式,所以我们是通过修改 config.js 配置文件的方式应用到自己的项目中的。

visual.js 虽然是核心文件,但作者将部分示例中的代码也包含其中,但并不影响我们直接在自己的项目中引用。

以下是 config.js 中的主要属性:

属性说明参考值
encoding数据源(csv、json)等的文件编码GBK / UTF-8 等
max_number每个时间节点最多显示的条目数10
showMessage控制是否显示顶部附加信息文字true / false
auto_sort时间自动排序(详细含义、作用及限制见代码中注释)true / false
timeFormat时间格式,显示于图表右下角的时间%Y、%Y-%M-%D 等
reverse是否倒序true / false
divide_by类型根据什么字段区分?如果是 name,则关闭类型显示
divide_color_by

颜色根据什么字段区分?

须要注意的是,如果配置成 name,则各条颜色不同(因为 name 值各异),如果配置成 type 等,那么相同 type 值的条颜色相同。

字段名
color指定部分或所有条的颜色,该项与 divide_color_by 设置有关。

以 divide_color_by = 'name' 为例,"中国"是其中的一项 name 值,那么该项将显示 #D62728 色:

color: {

      '中国': '#D62728'

}

changeable_color若 true 则颜色的深浅将根据数据的增长率实时改变
itemLabel
左边文字
typeLabel右边文字
item_x


interval_time
时间点间隔时间2
text_y


text_x


offset


display_barInfo如果希望不显示,则可以设置较大的值,单位像素
use_counter

step

format格式化数值
left_margin

right_margin

top_margin

bottom_margin

dateLabel_x

dateLabel_y

allow_up

enter_from_0

big_value

use_semilogarithmic_coordinate

long

wait数据加载完成后开始播放前的等待时间0
update_rate


xoyozo 7 年前
10,197

System.ArgumentException:“路由集合中已存在名为“HelpPage_Default”的路由。路由名称必须唯一。”

解决方法:删除 bin 目录。若无法删除,先在任务管理器中结束“VBCSCompiler.exe”进程。

xoyozo 7 年前
15,715

MozillaWiki 中推荐了三种配置,分别是现代兼容性、中级兼容性(默认)和旧的向后兼容性。


现代兼容性
对于不需要向后兼容性的服务,以下参数提供更高级别的安全性。 此配置与 Windows 7,Edge,Opera 17,Safari 9,Android 5.0 和 Java 8 上的 Firefox 27,Chrome 30,IE 11 兼容。

listen 443 ssl http2;
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;


中级兼容性(默认)
对于不需要与旧客户端(主要是 WinXP)兼容但仍需要支持各种客户端的服务,建议使用此配置。 它与 Firefox 1,Chrome 1,IE 7,Opera 5 和 Safari 1 兼容。(推荐)

listen 443 ssl http2;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;


旧的向后兼容性
这是旧的密码组件,它主要工作在 Windows XP / IE6 中,如果不是特别需要,建议放弃此配置。

listen 443 ssl http2;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1 SSLv3;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;


一般情况下,使用中级兼容性(默认)的配置即可启用 HTTP2,你还可以通过 mozilla 的 Server side TLS Tools 根据你的服务器进行详细配置。


F
转自 F2EX 8 年前
15,331