所有由罗佳(博主)发布的文章

[nginx]the “listen … http2” directive is deprecated, use the “http2” directive instead

新版本nginx出现了标题上的提示,其实就是把http2配置从listen指令里分出来了,修改方法很简单,只要把原来的http2去掉,然后在下面加一个http2 on;就行了。

原来:

server {
    listen [::]:443 http2 ssl;
    .....
}

改为:

server {
    listen [::]:443 ssl;
    http2 on;
    .....
}

就这么简单,但我为什么要写这篇?因为我搜索这个警告的时候发现搜索结果全是清一色抄的同一篇错误的文章,那篇垃圾文章莫名其妙让你删除http2就完事了,对如何添加这个新指令只字不提,看得我来气。

解决硬盘设备变成SCSI设备后在CrystalDiskInfo里不显示的问题

前几天买了一块宏碁掠夺者GM7 4T版本,回来装到主板上的第二m.2硬盘位之后发现进系统在CrystalDiskInfo(以下简称CDI)里不显示,不管怎么调设置怎么重新扫描都不出来,于是我看了一下磁盘精灵(DiskGenius),发现里面竟然显示这个盘的接口是SATA,我知道这肯定是这软件的判断错误,但不知道到底是哪里出了问题。

网上查了下,说和AHCI还有RAID模式有关,进bios里看了一下它里面关于AHCI什么的设置只和SATA接口的硬盘有关,而且调了也没解决这个nvme ssd被识别成SCSI设备的问题,于是我怀疑是不是这个第二m.2接口接上去就是会变成这样的,我就把主m.2槽的系统盘和它对调了一下,这下好了,俩盘都变成SCSI设备了。然后我还作死尝试删除驱动让它重新识别成nvme设备,结果就是一个下午加上晚上3小时我都在修复系统,因为转完loading的圈圈电脑就会直接重启,看了一下启动日志是加载完disk.sys之后其它的所有驱动就都无法加载了,显然是加载了disk驱动之后对硬盘的读写就出现了错误,当然和我删除的驱动有关。

后来我好不容易通过其它电脑开虚拟机把这个盘里的系统覆盖安装了,装回主机里成功启动后打开CDI看了一下发现所有盘都扫描不到了,我想起来是bios里把ACHI切成RAID了,但现在切回ACHI我的系统又进不去了,我开始怀疑会不会其实有一个驱动可以让硬盘就在SCSI控制器下正常工作,所以我翻了一下AMD官网上我这个主板芯片组的驱动列表,发现确实有和raid有关的驱动,装好之后所有的硬盘就都可以在CDI里显示出来了。我觉得这里要批评微星的主板驱动列表,放驱动也不放全,如果他那有这驱动我一开始就打上了,就没后面那么多事情了。

虽然现在我所有的硬盘都不小心被我变成SCSI设备了,不过只要装好驱动其实也是照常用的,也能正确获取SMART信息。最开始我发现网上也有不少人问硬盘变成SCSI设备了怎么改回来,因为没相关驱动的时候CDI等软件是无法获取硬盘的SMART信息的,这样对于硬盘的健康状态就心里没底,虽然我还是不知道要怎么改回来,不过把RAID驱动装好也是一个解决方案,虽然我们用不上它raid的功能,但它提供了获取这些信息的接口。

[node.js]同时使用canvas模块和sharp模块出现“The specified procedure could not be found”错误

升级到最新的node之后这俩模块是彻底没法共存了,之前还能通过降级其中一个模块来兼容一下,现在我怎么试都没法成功运行了,于是尝试找解决方案。

然后我发现这是由于两个模块使用的同名链接库不兼容导致的其中一个模块报错,似乎就是个无解的问题,偶然发现一个替代方案:https://github.com/Brooooooklyn/canvas

如果本来只使用了标准的绘制功能,那么可以连代码都不用改,直接替换掉依赖就可以解决问题,如果使用了非标准canvas方法,那么可能需要做一些小修改,比如将图片导出为png等格式时的额外参数之类的情况。

基本上要进行的操作就是删除package.json中的canvas依赖那行,然后直接执行npm i @napi-rs/canvas,npm就会自动删除canvas模块并安装@napi-rs/canvas,然后把代码中的require("canvas")换成require("@napi-rs/canvas")即可。

使用css grid制作一个活跃度砖墙

我也不确定这个到底叫什么,就是Github那种根据提交的代码次数改变方块颜色的动态墙,在这里暂时就叫活跃度砖墙。

这篇文章早就想发了,不过最近沉迷看番,一直都没写,我制作的版本在这里可以看到:https://blist.9baka.cc/user/luojia

基本思路就是往一个 displaygrid 的容器里塞方块,让 grid grid-auto-flowcolumn ,这样方块就是纵向排列的了,然后用 grid-template-rows: repeat(8, 1fr) 把行数分成固定的8份,列数会自动根据格子数量增加,最后对所有砖头使用 aspect-ratio: 1/1 来把它们固定为正方形(当然你要别的形状也可以),样实现的墙里面的格子可以自动根据整体的宽度改变大小。

和Github以及大多数地方不同的是,我用颜色把每个月区分开了,这样看起来更直观一些。

效果如图

继续阅读使用css grid制作一个活跃度砖墙

伪装成TiWorker.exe的病毒

我的surfacebook不知道从什么时候开始,只要一会儿不操作就会开始风扇狂转,每次风扇开始狂转我都会尝试查找到底是什么东西在抽风。

我用了很多办法,像是蹲守任务管理器,蹲守任务计划的正在运行的任务都找不到到底是哪个程序在抽风,最终用process explorer定位到有时候是一个TiWorker.exe进程,有的时候是System进程,然后又打开System进程的线程列表观察,只能等它抽风,因为鼠标一动就会停止,System进程里抽风的线程名称我忘了,只记得我查过它的用处好像是在空闲时间优化.net框架下的什么东西。然后我又查了一下关于TiWorker.exe的异常行为,基本都说是windows更新在电脑空闲的时候执行更新任务,我就信了。

接着就是很长时间我都没再管这个问题,想想更新就更吧,顶多就是风扇开始狂转的时候动一下鼠标就停了。

但是昨天我才发现我的电脑根本就不能进入睡眠状态了,就算是我手动点睡眠,它也只是屏幕黑掉之后开始风扇狂转。我就觉得这肯定不对了,再怎么样更新也不会在你点了睡眠之后开始更,而且除非我手动再次点亮屏幕,否则风扇根本就不会停下来。 继续阅读伪装成TiWorker.exe的病毒

[MySQL]在一个update语句中对不同的行更新不同的数据

mysql中update的基础用法是update 表 set 列1=?,列2=?,... where 筛选条件,这样的语句一次只可以对符合条件的所有行更新相同的数据,但update语句还可以join其它的表,从别的表读取数据更新到对应的行上,这样就可以实现对不同的行更新不同的数据,如下:

update
	表名 as t1
	inner join 表2 as t2      #也可以left join 或 right join 或 join,这里的join和select里面那个join用法是一样的
	on t1.id列名=t2.id列名
set
	t1.列1 = t2.列1,
	t1.列2 = t2.列2

虽然上面的方法能实现标题的要求,但总不能先把数据插入一个表再这样update吧,于是我想了一会儿,想到如果要提交多组数据肯定要把数据结构化,如果要提交结构化数据那肯定是要用json,mysql 的json函数里有一个JSON_TABLE函数可以用来把一个json转换成一个表类型,那么这个方法就好实现了,只要把上面的表2替换成用JSON_TABLE生成的表,就可以通过直接向mysql提供一个json来对不同的行更新不同的数据了,如下:

update
	表名 as t1
	inner join JSON_TABLE(
		?,
		'$[*]' COLUMNS (    #把json作为一个数组遍历,提取每个子数组作为数据源
			id列名 BIGINT PATH '$[0]',    #提取子数组第一个元素,取名为"id列名",类型是BIGINT,建议取名为目标表中的id列名,这样方便用using
			列1 INT PATH '$[1]',          #提取子数组第二个元素,取名为"列1",类型是INT
			列2 VARCHAR PATH '$[2]'       #提取子数组第三个元素,取名为"列2",类型是VARCHAR
		)
	) as t2 using(id列名)       #这个using是前一个例子中on语法的一种简写,用法参考官方文档
set
	t1.列1 = t2.列1,
	t1.列2 = t2.列2;

在 ? 的位置填入一个json字符串或者prepare这个语句后提交一个json字符串,就可以啦。json字符串示例如下:

[
	[1,20,"张三"],
	[2,24,"李四"],
	[3,18,"王五"],
	[4,23,"赵六"],
	[5,55,"小二"],
	[6,60,"poi"]
]

这样每个子数组中的第一个项目被提取为”id列名”,第二个为”列1″,第三个为”列2″(都是在上面的sql里的JSON_TABLE里取的名字),对应的值在set语句里被赋值到对应的行上,功能就完成啦。

[stable-diffusion-webui]更新所有扩展 脚本

适用于由git安装的扩展,把这个bat文件放在stable-diffusion-webui的目录下,然后执行即可更新所有扩展。(需要电脑上安装有git)

和webui本身自带的更新功能相比,这个脚本的优点是所有扩展是并行更新的,比webui那种一个个的更新快到不知道哪去了。

注1:更新扩展前请先关闭webui。

注2:并不建议没事去更新插件和webui本体,因为这些项目的更新和合并都很随便,并没有严格的兼容性测试和问题测试,所以有一定的概率更新完就不能正常启动了。

docker中的wordpress提示“您的站点不能完成环回请求”

我一直到刚刚才发现我的blog已经好久没给我发送自动备份了,然后后台里找了找原因,发现在“站点健康”页面显示“您的站点不能完成环回请求”,然后下面还有别的提示表示因为这个原因,定时任务无法启动。

于是我开始找为什么它会无法发送请求给自己,进到容器里用curl -v请求本站,发现域名解析到了容器的IP地址,但容器上开放的端口并不是443,所以会出现“Connection refused”错误。

然后再继续找为什么域名会被解析到容器ip,猜想肯定和docker的某些策略有关,搜了一下,原来是因为我给它使用了自定义网络,和默认网络不同的是自定义网络里容器名会被用于同网络中域名的dns解析,我的容器名就是luojia.me,结果就是wordpress请求自己的地址时被解析到了容器ip,导致请求失败。

解决方式就是把容器名换掉,比如加个前缀之类的就解决了。

[vue-router]点击链接导航后组件不刷新

这一个奇怪的bug困扰了我2天半,浪费了我很多时间来反复修改调试找问题,最后虽然找到了问题点,但是依然不知道是怎么发生的。

和网上很多其它能找到的页面不刷新的问题不同,他们要么是忘了写<router-view>,要么就是靠给<router-view>加key来解决缓存问题。而我这里的症状是页面加载后直接显示了最后一个路由的内容,不管点哪个链接都会显示最后添加的路由组件的内容。

最后我在控制台打出了所有组件的渲染函数和data函数才发现,并不是vue在渲染时选错了渲染对象,而是所有组件的渲染函数和data函数都直接指向了最后一个路由的函数,但我并没有代码去动态修改这些组件的函数,于是我在某个组件的data函数里填了一点数据再测试,问题就解决了。

由于是测试组件,原本data返回的对象是空的,像这样:

export default {
	data() {
		return {

		};
	},
}

填完数据之后变成这样:

export default {
	data() {
		return {
			poi:'poipoi',
		};
	},
}

然后这一个组件里面就不会自动变成最后一个路由组件的render函数和data函数了,但如果两个组件里面data返回的对象填写的内容也一样,那么前一个组件里面的这两个函数依然会指向后一个的,这在代码逻辑上怎么都讲不通,只能说应该是在某个优化环节出问题了,把字面一样的函数直接简化成了同一个,然后就产生了这种所有路由组件全部渲染出最后一个组件的内容的情况。

 

[expressjs]捕获路由和中间件的异步错误

express本身可以写async函数作为路由或者中间件(以下简称路由)使用,但如果在其中直接抛出异步错误的话则不会被捕获并传递给错误处理路由,需要在每一个async路由中手动写try/catch来捕获并处理错误,这显然对于拥有统一错误处理逻辑的框架是不友好的。

我不知道为什么express始终没有在4.x版本添加这个支持,看起来这应该并不会导致什么兼容性问题,即使不默认全局开启这个功能,也可以添加一个选项或开关函数来允许使用者开启异步错误捕获,但它始终没有这么做。

在这之前npm上也已经有一些可以实现这个功能的补丁包,不过它们几乎都是给创建出的app实例的所有相关路由方法套了一层壳在里面try/catch错误,导致如果是自己用一些特殊方法创建的路由对象,就失效了。

我原本用了一个直接修改express源码中相关原型方法的包,叫做express-async-errors,不过这个包没考虑到项目引用其它位置的express包的情况,它直接在代码中对相关源文件进行了require,导致无法作用于项目外依赖库的express,所以我重写了一个,而且源码比它还要简单,因为我直接把Layer类的handle方法改成了async函数,然后在里面await我们的路由函数,目前还没发现什么副作用,在我的项目中直接使用没有出现问题。

包地址:express-async-error-patch

asyncPatch函数需要传入一个创建出来的app实例, 为的是能获取到app所属的express包里的构造函数,不是为了在实例上包装方法。该函数在任何阶段调用都可以,只要在处理请求前调用即可。

2023

大家新年快乐!

我的新冠总算是阴了,但还有些咳嗽,可能是老毛病了。

2022年依然没有做完什么大事,琐碎的事情一大堆,而且还经历了几个电视剧里才能看到的剧情。只能说虽然自己没做什么,但生活经历真实丰富。

虽然按照现在冠状病毒的变异和治病效果来看,2023年总体上肯定也是乱七八糟的一年,不过还是祝大家能安安稳稳度过!