Hi there 欢迎 👋

大学狗; 谷粉

🌈 希望每人都是一束光,每人也都可以被照亮

🌎 Believe in OPENNESS

Nginx HTTPS 性能优化

启于 一开始源于一个一闪而过的想法——反向代理是否会引入额外的延时?然后进一步思考:倘若 CDN 使用 https 回源,然后又用 https 反代,这光是握手是不是就得来回十几遍才行? 显然,放弃 https 不是一个合理的做法(事实上是一个疯狂的做法),那么就研究了一下 https 的优化思路,整合了一些网上的资源,在此记录一下。 以下配置并不适用于所有情况,最典型的,CDN 不提供某些配置选项,我们只能把我们掌控之下的事情做好。 一些思路 HTTP2 HTTP1.1 发布于1999年,已经是上个世纪的东西了。当时智能手机、自动驾驶还停留在科幻作品里。然而20年后的今年,那些曾经处于幻想中的设备,竟然还在使用当初的协议… 我们知道 TCP 的反复握手总是很恶心。一个网页往往有含有大量的资源,于是很多时间被浪费在建立连接上,可以到这个网站测试感受一下。对于 HTTP2,同域名只建立1个 TCP 连接,也就是说握手再也不会充斥我们的网路了。当然,还有其他优点,这里不再一一列举。 启用 HTTP2 很简单,加上一个标志即可: listen 443 ssl; # 旧配置,改成下面这行 listen 443 ssl http2; 多数 CDN 应该支持此功能。 这个工具可以检测 HTTP2 以及下面几个配置项的状态。 启用 OCSP Stapling (装订) 对于个人站长,这个也许是作用最明显的了。由于一些不可描述的原因,Let’s Encrypt 的证书验证服务器从中国大陆访问不是很稳定。通常客户端会按照 OSCP 协议去查询证书的状态(以免证书被吊销但本地的吊销列表没有及时更新),如果这一步骤很慢,则直接影响整体加载速度。 启用 OCSP Stapling 后,服务器会预先查询自己证书的状态,将带有 CA 签名的结果缓存在本地,与证书链一并发送给客户端,这样客户端不需要自己再进行请求,只要验证合法性即可。也就避免了网络因素导致的延时。 启用方法也不复杂,加上三行配置: ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /path/to/full_chain.pem; # 完整证书链 多数 CDN 应该支持此功能。...

September 5, 2021 · Chenhe

不可描述的东西

都说啦不可描述啦~

August 27, 2021 · Chenhe

面向萌新的位与 0xFF 解释

TL; DR 0xFF 通常用于过滤,也叫掩码。和它进行与运算,结果是只保留一个数据的最低8位,其他位全部置0。 背景 在位运算中经常看到A & 0xFF 的身影,甚至已经成了习惯性动作,但一直没有深究它的具体意义,直到这次忘记了神奇的 0xFF,于是发生了很糟糕的事情… 本来是一个很简单的需求——将 int 转为字节数组,然后再转换回来。为了不误导大家,这里先给出正确的实现(kotlin): fun Int.toBytes(bytes: ByteArray? = null): ByteArray { val result = bytes ?: ByteArray(4) if (result.size < 4) { throw IllegalArgumentException("bytes capacity must >= 4") } result[0] = (this shr 24).toByte() result[1] = (this shr 16).toByte() result[2] = (this shr 8).toByte() result[3] = this.toByte() return result } fun ByteArray.toInt(): Int { if (this.size < 4) { throw IllegalArgumentException("bytes size must >= 4") } return ((this[0]....

August 19, 2021 · Chenhe

利用GHActions部署hugo博客到自己VPS

受够了 Wordpress 的臃肿以及对 markdown 的水土不服,受不了 ghost 主题的匮乏与对中文圈的态度。Hexo 用过一段时间,但实在太讨厌 NPM 了,只想安安静静写个博客,结果竟然还要配“开发环境”? 于是 —— Go 真香!迁移到了 Hugo。和 Hexo 一样作为一个静态网站生成器,集成 Github Pages 几乎是标配了,但是 GH 近期在大陆似乎不太如意,眼看着就差彻底断联了。所以还是更想放在自己的香港 VPS 上。作为踩坑记录,这篇文章出现了。 上传文件到 VPS 因为 hugo 生成本身非常容易,就一行命令的事,所以我们先来解决主要矛盾,那就是怎么把生成的文件放到 VPS 上。 rsync 当然,你大可以配一下 Hook,GH 生成完毕后打包传到 Release 或其他什么鬼地方,通知服务器,然后服务器再去拉取回来解压。显然,这不是一个「优雅」的方案。 我希望这一步尽可能地简单,简单到无序通知 VPS 进行额外操作,GH 可以单方面部署完成,这样就少了许多维护成本与不稳定因素。既然是文件传输,自然想到 FTP SFTP/SCP。这两个其实都行啦,不过这里都不用 😂,而且另一个更加适合此场景的东西——rsync。这是一个文件同步服务,可以进行差异比较只传输必要部分,和其他一堆现代化的特性,有兴趣自己查查看吧 标准的服务器系统应该预置了 rsync(不要告诉我你使用 windows),这东西用起来和 scp 很像——都是借用 ssh 进行传输,也使用系统账户进行认证。一条命令轻松实现需求 -a 表示递归同步,并且同步元数据 -v 打印一些信息 --delete 删除目标文件夹存在但本地不存在的玩意,不加这个参数就是增量同步。你一定不希望删掉某个不可描述的东西后实际上文件还在那吧 😄 rsync -av --delete source/ username@host:destination (才怪)难道你的服务器不要身份验证了? 你可以直接把 VPS root 的用户名密码,或者密钥拿过来使,又不是不能用。但是我 觉得 肯定这不是个好主意。新建个系统用户?然后 balabala…...

August 16, 2021 · Chenhe

Springdoc 生成 API 文档 — 迁移自 Springfox

傻傻分不清的近义词辨析 提到 Spring 自动生成 API 文档,多数人脑中就浮现出几个单词:Swagger, OpenAPI, Springfox… 所以首先有必要搞清楚他们的关系。 Open

June 19, 2021 · Chenhe

[译] Mocks 与 Stubs 的区别

原始链接:https://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs 很多人经常会混淆这两个测试用的术语,要想完全理解测试替身(test doubles)的用法,我们就必须搞清楚 mocks 和其他术语的区别。当我们进行测试的时候,通常一次只关注一个元素,所以产生了一个术语叫单元测试。问题在于为了使得某个独立单元工作,通常需要其他单元的配合,因此在这个情况下我们需要某种类型的替代品。 在上文(见原文)提到的两个测试类型中,前者使用的是一个真实的对象,而后者使用的是一个 mock 对象,也就是非真实的。使用 mock 是在测试中避免使用真实对象的方法之一,同时也有其他形式的模拟手段。描述这些手段的词汇就很繁杂了,比如 stub, mock, fake, dummy。在这篇文章中,我使用 Gerard Meszaros 的书中所定义的词汇,虽然不是每个人都认可他,但我比较赞同。 Meszaros 使用 Test Double 这个术语来描述任何一个在测试中用于代替真实对象的虚拟对象,这个名称源于电影中替身演员的概念。随后 Meszaros 定义了五种典型的虚拟对象: Dummy 被传递但从不使用,通常只用于填充形式参数。 Fake 则具有可以正常工作的实现,但通常采用了一些不适合生产环境的便捷手段。(一个典型例子是内存数据库)。 Stub 在测试中总是返回固定的返回值,对于与测试无关的代码,通常直接忽略。 Spy 和 Stub 一样,但是它会记录自身被调用的情况。一个例子是邮件服务会记录发送了多少封邮件。 Mock 就是我们这里所谈论的:它根据预先编写的逻辑,基于调用者所期望的返回值。 在所有这些类型中,只有 mock 进行行为验证,而其他类型的虚拟对象通常只能进行状态验证。和其他类型一样,mock 在测试过程中也具有一些行为,以便让待测程序正常工作,但在设置和验证阶段有所不同。 为了进一步研究测试替身,我们需要扩展一下之前的例子。很多人只在真实的对象难以配合进行测试时才会使用测试替身。比如一个常见的用例:如果订单异常,那么就需要发送一封邮件通知。问题是在测试期间我们并不想真正给客户发一封邮件过去,所以我们为邮件系统创建一个我们可以控制操作的测试替身。 现在我们可以来研究 mock 和 stub 之间的区别了。假设我们正为发送邮件这一行为编写测试,代码大致如下: public interface MailService { public void send (Message msg); } public class MailServiceStub implements MailService { private List<Message> messages = new ArrayList<Message>(); public void send (Message msg) { messages....

January 9, 2021 · Chenhe

互联网时代如何彻底拉黑一个人

现在账户太多啦噜,想彻底和一个人断绝关系还真是不容易。 所以这里就记录一下吧,以备不时之需。 以下所有情况均应当考虑到小号问题 常用部分 手机号:先加入黑名单(或者运营商云拦截黑名单),然后删除。 电子邮箱:加入黑名单。 微信:先拉黑后删除。 QQ:直接删除。 支付宝:先拉黑后删除。 淘宝:直接删除、删除相关收件地址。 其他服务 微博:直接拉黑。 百度网盘、贴吧:删除拉黑。 相册、云相册(QQ空间相册、微信朋友圈相册、百度网盘、时光相册、一刻相册):删除相关照片、退出相关共享影集。注意删除相关聊天的截图。 闲鱼:取消关注、拉黑。 京东:删除相关收件地址。 12306、携程、去哪、飞猪:删除相关旅客信息。 国际服务 Google:GMAIL 拉黑,PHOTOS 删除相关照片,退出家庭组。 Github:取消关注、取消星标。 Telegram:为对方删除聊天记录、删除联系人。 Facebook:拉黑。 Twitter:拉黑。 iCloud:拉黑、删除相关备份数据。

December 24, 2020 · Chenhe

详解三星OneUI后台与电池管理设置项

三星 OneUI 的应用自启与后台权限,以及电源管理一直比较乱(但关联关系做的比较智能)。其实也不仅是三星,Google 对大陆的流氓应用一直后知后觉,尽管近期多个系统底层更新不断收紧这方面政策,但脚步还是太慢,与此同时也造成不同系统版本(也称 API 等级)对后台的限制不一样,也就导致了许多云里雾里的设置。 这些本就零散的设置,再加上厂商对中国区的优化,还有翻译的不同,许多原因共同作用最终导致了 OneUI 这样的局面。其实如果能正确理解并应用这些设置,不仅能最大化省电,甚至在某些条件下还能够收到通知推送。我根据实验以及作为业余 Android 开发者的经验,总结下不同设置的实际意义。 **首先强调,网上目前大部分解读都是错误的,但依然感谢分享的同学为之做出的努力。**我也不能保证下面的解释完全正确,欢迎大佬指正。 设置项总览 以国行三星 S10 OneUI 2.5 为例。 三星与应用自启、后台、耗电优化相关的设置项入口一共有7个,他们分别是: 智能管理器 - 自动运行应用程序 设置 - 常规管理 - 电池 - 用电管理 - 自动运行应用程序 设置 - 应用程序 - 某个应用 - 电池 - 允许后台活动 设置 - 常规管理 - 电池 - 用电管理 - 深度休眠应用程序 设置 - 常规管理 - 电池 - 用电管理 - 让未使用的应用程序进入休眠 设置 - 应用程序 - 某个应用 - 电池 - 优化电池使用量 设置 - 应用程序 - 右上角菜单 - 特殊访问 - 优化电池使用量 这7个入口中实际上只有3个具体功能:其中 [1, 2, 3] 是一回事,暂且称之为自启与后台;[4, 5] 是一回事,暂且称之为休眠;[6, 7] 是一回事,称之为优化电池使用量。...

October 26, 2020 · Chenhe

「QQ 沉默者」白皮书

序 「QQ 沉默者」是一款针对 QQ 的插件,实际上经历了数个产品形态,是一个典型的极端思想的产物。从2020年2月有了初步想法,至今(2020年9月)虽然从未公开发布,但我自己也是断断续续地使用改进了大半年。偶然得知列表里竟然还有人真的在寻求这样一个功能,所以我决定把这半年来的收获分享一下,希望不要有人步我的后尘,也当做是不愿意公开发布的一个解释。 这里不会涉及到很多的技术问题,相反,我更想从初衷与结果的角度谈一谈。 TL;DR 对经常不回消息的人,我们也不回他们的消息。以暴制暴的「QQ 沉默者」没能像想象中构建轻松的聊天氛围,相反,强化了独裁者的报复心态。它不是什么正义的神器,而是一个潘多拉盒子,打开之后容易让人为之着魔、疯狂。 同样对经常不回消息很气愤的朋友,希望你们能先了解聊天的目的与本质,沟通是为了解决问题,交流是为了增进感情。如果不能,删除或者再也不见或许是对大家最好的办法。不要尝试以暴制暴,如果成功了,你会陷入暴力的沼泽;如果失败了你要承受长久的内疚。 既然不合适,就天各一方,没必要指责或强求。更没必要给自己找不悦。 起 QQ 沉默者初衷是解决某些人屡次无故不回消息,或沟通过程中常常突然消失而后了无音讯的问题。相信每个人都会有类似的体验,甚至某些自己就喜欢不回消息却刷朋友圈的人同样讨厌这种经历。他们总是有意无意地不回消息,并将其调侃为「意念回复」,试图娱乐化给另一方带来的困扰,而我们始终没有一个良好的反制策略。我大致分析了一下,这通常与性格和长期的成长环境有较大关系,粗俗地讲就是「狗改不了吃屎」(当然我这里意思不是把这类人比喻为 :dog: 你们懂就好)。 很多次气急败坏地想删掉好友,但又觉得很不妥;无数次下定决心再也不要找他,却又按捺不住躁动的心以及有消息必回的强迫症。终于,有一个折中的办法——以其人之道还治其人之身。 既然你回复慢,那我就回复得和你一样慢,甚至更慢 ╯^╰ 我也许不是第一个有这种想法的人,但可能真的是第一个付诸行动的人。 变 最狠的第一版 既然愿意投入精力去做这样一个有点匪夷所思的插件,大家也应该就能感受到我对于这种行为的憎恶是多么强烈。一开始我只是想惩罚一下那些穷凶极恶的人,但在开发过程中,由于技术的限制以及…思想的强化?这种愤怒逐渐转嫁到了更广泛的好友身上,以至于最终干脆砍掉了白名单,强制性地对所有好友生效——不论你是客户、老师、同学、朋友,没有什么好商量的。相应的,「屡次」「无故」也不再是遭到反制的门槛,毕竟通过现有技术难以自动化界定这些标准。 于是第一个雏形就这么出来了:它粗暴地统计每个人的平均回复时间,不分对象不论缘由地对所有人套用规则。不得不承认,这很爽。**关键在于这个「爽」似乎不是来自解决了问题的兴奋,而是报复后仇恨的迸发——就像被人扇了一巴掌,你把他打倒在地连扇20巴掌一样。**结果自然也不言而喻。 人性的第二版 成人们都知道世界不是非黑即白的,那就也不应当对延时回复一概而论。法律上讲究疑罪从无,显然一开始的做法于情于理都说不过去,于是我决定给自己一个机会。现在每一次发送都可以指定为立即发送,当然,默认情况下还是根据平均回复时间来延时。 说它人性是因为没有机械地套用算法,有了人类的参与,对事情的处理或多或少不会再那么僵硬。 然而我错了。**这次改进其实使整个项目的方向从「技术向善地解决问题」转向了「独裁思维的控制与报复」。**表面上我可以根据实际情况选择暂时容忍他的小调皮,实际上相当于把自己推上了独裁者的宝座,因为我掌握着“生杀大权”,原本为了避免误判才点击的立即发送,不知不觉间好像成了一种恩惠。 既然我如此善良地放过你了这一次,难道你不应该感激我吗? 这种想法从局外人的角度看很可笑,要想感同身受,大家不妨类比一下溥仪在新中国成立后逛故宫也要买票。 后来逐步又改了许多,包括区分开首次建立对话的回复时间与后续聊天的回复时间;定期清零平均时间;低于阈值不触发延时等等。但这些措施没能把项目拉回正轨。 灭 最后我意识到,自己做的是不是太过火了,但这并不是一开始的初衷啊。**聊天氛围完全没有因此变得轻松,相反,更加紧张了。**于是干脆去掉了延时功能,只保留回复时间统计作为参考,试图让一切回到最初的样子。 正是这次更改,我才发现了问题的根源所在。原本不回消息只是少数人的行为,我们应该关注的焦点是不回消息背后的原因与态度,而不是回复时间这一冷冰冰的数字。前几天有一个掀起波澜的文章《外卖骑手,困在系统里》,当中有一端话: 而在整个系统中,最无解的部分在于,在让骑手们越跑越快的推手中,也包括骑手自己。 孙萍说,系统要求骑手越跑越快,而骑手们在超时的惩戒面前,也会尽力去满足系统的要求,「外卖员的劳动越来越快,也变相帮助系统增加了越来越多的『短时长数据』,数据是算法的基础,它会去训练算法,当算法发现原来大家都越来越快,它也会再次加速。」 相比较2月份,现在的我对回复时间的容忍度已经大幅下降,并且不再满足于曾经那些可以理解的合理理由——毕竟有多么紧急的事能让人忙到连10秒钟回个「一会再说」都来不及呢?**这一变化的推手正是 QQ 沉默者插件本身。**它给我罗列了统计数据,把选择权交给了我,慢慢的我眼中只剩下数据。哪怕现在没有了延时功能,光是盯着这些数据甚至都觉得怒火中烧——竟然半小时都没有回复。 最后 对于不回消息的执拗,我已经被自己开发的插件强化了难以形容的极端,并在痛苦中挣扎。理想中和谐的聊天氛围遥遥无期,原本较为和谐的氛围也毁于一旦,剩下的只有不安、猜疑和报复。**「QQ 沉默者」不是什么正义的神器,它是一个潘多拉盒子,打开之后容易让人为之着魔、疯狂。**假设大部分的人都安装了这样一个插件,QQ 也将变成黑暗森林,所有人总体的平均回复时间终究会越来越长,而 QQ 也将趋于冷寂。 但是以上不代表我对初衷的否定。 现在我已经关闭了这个插件,尝试着不去关注那些数据。而那些经常性不回消息转头刷个空间的人已经删掉了。我同样看过一篇文章《我为什么有时候不回你消息?》,可能真的是习惯想法不同,看完后没有丝毫理解,只有厌恶,没想到竟然有人能把不回消息讲的那么理所当然,甚至还把自己塑造成一个受害者的形象。 和我有一样感觉甚至希望得到这个插件的朋友,希望我们都能先了解聊天的目的与本质,沟通是为了解决问题,交流是为了增进感情。如果不能,删除或者再也不见或许是对大家最好的办法。不要尝试以暴制暴,如果成功了,你会陷入暴力的沼泽;如果失败了你要承受长久的内疚。 与自己合拍的朋友在一起,感受下美好;对不合拍的同事宽容,展现出大度。不要成为第二个我,这个项目就此终结,这也算是最后的技术向善吧。

September 26, 2020 · Chenhe

Lean OpenWrt 编译使用小记

Lean OpenWrt 是 Lean 大佬修改的 OpenWrt 开源版本,和 KoolLede 是国内两个比较有名的分支。Lean OpenWrt 不提供预编译文件,所以想使用的话需要自己编译一遍。 编译需要使用 Ubuntu 系统,不要使用 WSL 会出问题。 编译没什么好说的,README 里面写的很详细一步步来就行了,推荐使用这个脚本白嫖下 Github 的服务器来云编译。 编译选项 如果没什么特别要求,保持默认就行,但来刷 Lean 的基本上都有一些奇奇怪怪的需求😁 这里有插件清单,包括 xls 格式的:https://www.right.com.cn/forum/thread-344825-1-1.html 酸乳饮料 Lean 内置的酸乳饮料插件很好用,而且没发布到官方源,也是很多同学来的目的。可惜现在默认给取消了,找回来分三步: 取消 feeds 注释。修改一下 feeds.conf.default 文件,去掉最后一行 helloword 的注释。重新执行 ./script/feeds update -a && ./script/feeds install -a. 如果是云编译,修改一下 diy-part1.sh 取消带 helloword 那一行的注释。 make menuconfig 生成配置文件的时候,在 LuCI - Applications 里选中 luci-app-***-plus. 系统安装完毕后如果找不到菜单,那命令行执行一下 0xDEADBEEF > /etc/config/google_fu_mode 就可以了。 IPv6 Lean OpenWrt 默认不支持 IPv6,启用的话在 Extra packages 里选中 ipv6helper 就好啦,所需的依赖会自动勾选。...

August 12, 2020 · Chenhe