0%

最近公司的服务遇到了个问题,一些内容在iOS里面需要十几二十秒的白屏之后才能显示正常。定位到最后发现是OCSP的问题。

OCSP是什么

OCSP(Online Certificate Status Protocol,在线证书状态协议)是一种用于检查数字证书状态的网络协议。OCSP的主要功能是验证证书的有效性,以确定其是否被吊销。

OCSP是作为证书吊销列表CRL而出现的。 CRL是一个维护已撤销证书的列表,由浏览器下载,检查客户端访问的网站证书是否被撤销。但随着证书越来越多,这种黑名单机制势必性能会变差,因此有了OCSP协议。

OCSP的工作流程

OCSP的工作流程大致如下:

  1. 客户端请求:客户端向OCSP服务器发送一个请求,包含需要验证的证书的标识信息。
  2. OCSP服务器响应:OCSP服务器查询其数据库,返回该证书的状态信息。
  3. 客户端处理:客户端根据OCSP服务器的响应,决定是否信任该证书。

image
图片来源

OCSP的优点包括:

  • 实时性:OCSP提供了实时的证书状态信息,而CRL可能会有延迟。
  • 效率:OCSP请求通常比下载整个CRL文件要小得多,节省了带宽和时间。

OCSP有一些潜在的缺点,例如:

  • 隐私问题:每次验证证书时,客户端需要与OCSP服务器通信,这可能会暴露用户的浏览行为。
  • 可用性问题:如果OCSP服务器不可用,客户端可能无法验证证书的状态。

OCSP Stapling

OCSP Stapling(OCSP 封套),是指服务端在证书链中包含颁发机构对证书的 OCSP 查询结果。这是一种向浏览器提供撤销信息的技术。证书stapling过程涉及将当前的OCSP响应附加到HTTPS连接中。这样,服务器和浏览器之间的流量就会减少,因为浏览器不再需要自行请求OCSP。这有助于解决上述的隐私和性能问题。

问题所在

OCSP一个最大的问题就是实时查询的时候,会影响到性能
公司使用的证书是Godaddy,Godaddy并没有中国区,所以中国iOS区域的用户在OCSP这一步出现了访问的时间延长。

image

查看网站证书概要

1
echo | openssl s_client -servername example.com -connect example.com:443 | openssl x509 -noout -issuer
image

处理方案

考虑到国内用户的体量与部署,我们最终将网站的证书切换到了有国内部署的global sign

reference

这本书我觉得读起来还是挺舒服的,没什么说教的味道,用一句现在比较流行话来说,就是没什么“爹味”。文风质朴,像在一个富有经验的长者对话。虽然不能有什么实质的改变。但是怎么说,一本书读下来之后,像享受了一场精神按摩,缓解了一些焦虑。

快乐和幸福是有区别,快乐代表轻松,而幸福是一种所谓的苦尽甘来,如此一说,幸福应该是一种比较级,而快乐则是一种状态。

关于读书,梁说我们现在的看书条件越好了,却不像以前那么投入。谈读书篇,他分享了几个技巧,我觉得非常有意义:

  1. 带着问题去阅读,当你带着疑问去读、去寻找答案时,自我的感受会更深刻。
  2. 了解作者背后的故事,每一本书,都有自己时代创作背景。
  3. 要自己多写,看书的时候,我们可能会觉得书里一些地方这不好那不好。只有自己去写了,我们才能发现问题。

书中聊到,当代年轻人,关于坐几个小时的高铁就好累,这比他以前坐几十个小时绿皮火车差远了。
这里我觉得跨时代比较是没有意义的,一个时代有一个时代的幸福感与苦难。我时常会觉得,当然人民生活水平比以前高了不是一丁半点,但是精神世界却越来越贫瘠,这里不是说不丰富,而是我们越来越焦虑了。就像那句话所说 “如果我不曾见过阳光,那么我原本可以忍受黑暗”

今天的年轻人,离自己向往的生活只有一步之遥,但是就这一步之遥跨不过去。他们内心里积累了这么多感受和愿意去探索的东西,但是行动上跟不上,暴风骤雨迎面而来的时候,就没有那个勇气。

当代的年轻人,有很多的可能性,但是从生活的轨迹看上去,却看不到什么可能性。这里的矛盾是:想得太多, 行动却太少。当这是正常的,因为我们正处于一个没有历史借鉴的时代。

书中给的许多建议我都觉得还是挺好,可能我们在这么忙碌工作中,也应该思考思考,是不是忽略了精神生活了。

最近读了一本书,名字叫《微习惯:简单到不可能失败的自我管理法则》。书很薄,内容也不复杂,不过感觉蛮有意思。书名非常概括,从书名我们也能大概猜到书中就会讲什么。

作者叫史蒂芬盖斯,是个名不见经传的普通宅男。起因是在2013年新年伊始,由于对过去的一年自我表现不太满意,作者打算在新的一年要提升锻炼的目标。于是打算花30分钟锻炼,可是刚开始一会就想要放弃了。于是作者就改变策略:”今天就做1个俯卧撑就行吧。“ 结果作者发现,非常轻松就完成了,甚至还想多做几个。如此反复几天下去,没想到反而达成的健身的目标。
于是作者发现通过微小的一步步养成习惯的策略非常有效,便把这段经历写成了一篇文章放到博客上,引起了热烈的反响。作者也从一个个的微习惯中培养出了真正的习惯, 某种程度上来说实现了对自己的逆袭。

微习惯是什么

总的来说,微习惯就是你强迫自己每天做的微不足道的积极行为。比如你想培养写作的习惯,你可以给自己设定目标,每天只写个50字;如果想培养阅读的习惯,可以给自己设定目标每天翻2页书。
微习惯策略行动,就是运用少量的意志力强迫自己做一件事情。 因为太小而不至于无法完成,因此,你不会有机会体验未完成目标导致的常见消极情绪 。

作者认为,很多时候人们无法让改变的效果持久下去时,会认为原因是在自己身上。其实,不一定是他们自己本身的问题,可能只是他们采取的策略不对而已。研究表明,人们总是会过高地高估自己的自控力。很多时候我们总陷入自己没有什么进步的自责之中,却没意识到可能是自己的策略出了问题。
而微习惯非常小,小到不可能失败。正是因为这个特性,它不会给你造成任何负担,并且具有超强的“欺骗性”,它也因此成了一种极其有效的习惯养成策略。

微习惯是如何起作用的

习惯形成的第一个信号是抵触情绪减弱。
行为要变成习惯,需要有一个过程,而变成过程之前,我们需要有两个途径来支撑我们的行为: 动力和意志力。

动力 & 意志力

动力跟意志力都可以让我们养成一个习惯,但动力和意志力不是非此即彼的,二者之间存在重要的关系。当你做事缺乏动力时,意志力的消耗量就会猛涨。意志力消耗量较高时,你会难以长期维持一个行为并将其培养成习惯。

image

动力并不靠谱

俗话说,一鼓作气,再而衰,三而竭。我们都经历过一种热情递减效应,比如吃第五块比萨时的愉悦感会略低于吃第四块时的,吃第四块时的又略低于吃第三块时的。再比如,可乐的第一口往往是最好喝的,越往后肥宅快乐水带来快乐效果会越减少。我们在进行重复行为时也存在同样的现象。
人们在做计划的时候经常性忽略了动力和精力水平可能会出现波动,以为在实际过程中能够一直保持当时的精神和精力状态。所以常常制定了一些实际上可能完成不了的目标。
所以,依靠动力的策略并不靠谱。不是说有动力不好,相比,如果我们想持久去改变,单靠动力并不是一个很可靠的策略。

意志力

比起动力来说,我们更应该依赖意志力,因为意志力有三个特点:

  1. 意志力可靠。当然,前提是我们能强迫自己
  2. 意志力可以被强化。和动力不一样,意志力可以像肌肉一样得到强化
  3. 意志力策略可以通过计划执行。如果你依赖动力,严格执行时间计划是很困难的。没人知道你执行的时候是否还有动力了。

所以,我们应该更多地去依靠我们的意志力。当然了,如果动力越足,我们越会消耗更少的意志力。但是,有一个问题,意志力是会损耗的。

微习惯为什么效果

引起意志力损耗的5大主要因素是:
• 努力程度
• 感知难度
• 消极情绪
• 主观疲劳
• 血糖水平
采用微习惯的方式,对这5点的损耗都非常低。书里举了一个生动的例子,微习惯像是习惯的一只特洛伊木马,悄悄潜入我们的大脑,让我们在比较低耗能的情况下,不知不觉把习惯给养成。

如何行动

既然微习惯有效,那我们应该如何去使用微习惯呢?书中给了几个步骤让我们培养微习惯

八大步骤: 培养成你的微习惯

1. 选择一个微习惯,制定每天的计划

鉴于微习惯对意志力的消耗很小,我们可以同时制定好几个微习惯。但是微习惯数量不要超过四个,因为那样太多了。数量越多,你的精力就会越分散,就越有可能忽略或者忘记其中一个。

作者提供了三种微习惯计划:一周弹性计划、单一微计划和多项微计划,以适应不同人的需求和能力。一周弹性计划建议从一个习惯开始,一周后根据个人感受调整计划。单一微计划专注于一个重要的习惯,适合意志力较弱或情绪低落的人。多项微计划则适合那些想同时培养多个习惯的人。

对于不适合每天执行的习惯,作者建议以周为单位来培养,这可能需要更长时间,但最终会形成稳定的模式。他还提出了混合微习惯的概念,即在两个选项之间选择,比如去健身房或者在家做一些简单的锻炼。这种策略提供了灵活性,同时鼓励每天都有所行动。

2. 挖掘习惯找到内在价值

通过多思考”为什么“,找到我们目标的来源。只有知道这个目标的价值,我们才能找到坚持下去的意义所在。
作者提出使用“为什么钻头”方法,即不断追问“为什么”直到找到行动背后的核心动机。这要求诚实地回答,直到找到核心理由。其实就是5Why分析法

3. 明确习惯依据,将其纳入日程

习惯依据通常有两种:时间和行为方式。对于日程规律的人,基于时间的习惯设置可能更有效;而对于日程灵活的人,基于行为方式可能更适合。我个人比较推崇的方式是基于时间的日程方式。

4. 建立回报机制,以奖励提升成就感

人们在感到满足和获得回报时更容易做出积极的决定,同样,如果一个行为没有明显的回报,大脑可能会抵制这个行为。这就是有时候一些重复的活动会让我们觉得很枯燥的原因。所以,每当我们有一点进步的时候,不妨给自己来点儿奖励,吃顿好的或者是其他娱乐形式放松一下。

5. 记录与追踪完成的情况

虽然不推荐流于形式,但是我个人还是推荐采用打卡的方式来记录。特别是以一个日历的形式来打卡,因为那样很直观。我个人就会以一份日历来记录自己的运动计划,曾经我在公司的健身房看过一个同事随手拿着一本小册子,每次练完卧推之后写点东西,应该是在记录自己的组别和次数。
总之,记录载体并不重要,只要能够直观与方便记录我们在慢慢变好就可以。

6. 微量开始,超额完成

微习惯不会让你有失败的借口,不会让你感觉到愧疚。既然定的目标轻而易举,我们能够很轻松或者是在不知不觉中就把任务给完成了。
设定小而易于实现的目标,这样做有几个好处:

  1. 强化意志力:通过频繁地完成小任务,我们可以逐渐增强意志力,就像健身房里通过多次举起较轻的重量来训练肌肉的持久性一样。
  2. 立即取得进步:微习惯策略允许我们立即看到进步,这本身就是一种激励。一旦开始行动,动力就会接管,减少对意志力的依赖。
  3. 避免耗尽意志力:微习惯的任务要求低到即使在意志力几乎耗尽的情况下也能完成,这样就避免了失败的借口和内疚感。

7. 服从计划安排,摆脱高期待值

从潜意识层面来看,在我们超额完成任务后,大脑的期待阈值可能会不知不觉被提高。作者不建议这样,不断提高期待值不是我们的目标,目标应该是放在能够长久坚持下去。

8. 留意习惯养成的标志

如果能够长期坚持微习惯,那么它将会在不知不觉中变成我们真正的习惯。变成真正的习惯的信号:

  1. 没有抵触的情绪
  2. 认同自己的拥有这个习惯的身份
  3. 对该行动不再考虑以及焦虑
  4. 已经将该行为常态化了
    当你的行为符合上面几点的时候,我们就成功培养了一个习惯。

总结

个人认为,这个微习惯有点另辟蹊径。我们自古有句话叫“取法乎上,仅得乎中” 。意思就是我们一开始定一个很高的目标,即使最终不能达成,也能得到一个中等的效果。而微习惯却走的是一个”取法乎下“的打法,但也可以让我们取得超预期的成果。但两者其实不违背,一种是鞭策的方式,而一种是激励的方式。

无论如何,培养一个习惯是长期坚持下来的结果,书中给了我们达成培养习惯目的另一种途径。如果你有过想培养一个习惯但是迟迟不能成功的经历,不妨试试书中提供的方式。
总而言之,微习惯,微量开始,超额完成,形成习惯,持之以恒。

参考

什么是Server Side Includes

我们来看看维基百科是怎么解释的:

服务器端内嵌Server Side Includes,亦简称为SSI)是一种大多数仅应用于互联网上的简单解释性服务器端脚本语言。
SSI最常见的用法是将一个或多个文件的内容包含在网页服务器的页面上。例如,一张包含每日报价的页面可以通过下面一段代码将报价单包含在页面中:

1
<!--#include virtual="../quote.txt" -->

SSI 简称代码片段,通过特殊的语法糖,服务器在响应的时候遇到相关指令,会发起另外的请求(subrequest)去请求对应的代码片段之后嵌入到父页面中,从而实现页面在服务端拼接

SSI 的运作机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  [Client]
|
| HTTP Request
v
[NGINX Server]
|
|--- [SSI Parser]
| |
| |----- [Include Header.html] // SSI 片段
| |
| |----- [Include Menu.html] // SSI 片段
| |
| |----- [Include Footer.html] // SSI 片段
|
v
[HTML Page]
|
| HTTP Response
v
[Client]

如何使用Server Side Includes

使用nginx ssi指令即可开启服务

1
2
3
http {
ssi on;
}

我们以nginx为例实现一个ssi 服务, 使用nginx 代理到 nodejs(这里我们称为upstream服务), 然后在nginx上面开启ssi 服务。

链路如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Client]
|
| HTTP Request
v
[NGINX Proxy]
|
| HTTP Request
v
[Upstream Server (Node.js)]
|
| HTTP Response
v
[NGINX Proxy]
|
| HTTP Response
v
[Client]

nginx设置代理

nginx 设置代理并开启ssi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
error_log logs/error.log debug;

events {
worker_connections 10;
}

http {
ssi on; # 这个指令表示开启ssi

upstream to_node {
server localhost:3000;
}

server {
listen 8080;
server_name localhost;

# proxy all request to node server
location / {
proxy_pass http://to_node;
}
}
}

upstream 服务直接响应html内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- index-static.html 内容 -->
<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<!--#include virtual="./header-block.html" -->
<h3>Hello world!</h3>
<!--#include virtual="./footer-block.html" -->
</body>
</html>

<!-- header-block.html 内容 -->
<header>
<h1>footer block from ssi</h1>
</header>

<!-- footer-block.html 内容 -->
<footer>
<div>footer block from ssi</div>
</footer>

然后打开页面

是不是很简单?

异常的出现

那么,对于SSI的使用数量,是否有上限呢?让我们往页面里面再添加SSI

修改如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<!--#include virtual="./header-block.html" -->
<h3>Hello world!</h3>
<!--#include virtual="./footer-block.html" -->
<!--#include virtual="./footer-block.html" -->
<!--#include virtual="./footer-block.html" -->
<!--#include virtual="./footer-block.html" -->
<!--#include virtual="./footer-block.html" -->
</body>
</html>

访问结果

oops 发生了什么事?

在nginx 的 error log里,我们发现问题所在

1
2
3
2024/06/24 19:41:34 [warn] 67237#15146903: 10 worker_connections are not enough, reusing connections
2024/06/24 19:41:34 [alert] 67237#15146903: *82 10 worker_connections are not enough while connecting to upstream, client: 127.0.0.1, server: localhost, request: "GET /html/index-static.html HTTP/1.1", subrequest: "/html/./footer-block.html", upstream: "http://127.0.0.1:3000/html/./footer-block.html", host: "localhost:8080"
2024/06/24 19:41:34 [alert] 67237#15146903: *82 10 worker_connections are not enough while connecting to upstream, client: 127.0.0.1, server: localhost, request: "GET /html/index-static.html HTTP/1.1", subrequest: "/html/./footer-block.html", upstream: "http://[::1]:3000/html/./footer-block.html", host: "localhost:8080"

worker_connections are not enough while connecting to upstream

小结

这里体现了ssi 的第一个特性: subrequest 同样也会消耗worker的数量
所以,ssi同样也会跟我们的父请求抢占worker资源,每个页面的SSI数量也需要严格进行限制。

对upstream的挑战

既然父请求与SSI都会占用worker数量的话,我们很容易想到,使用SSI的技术,对后端的流量会造成放大

实验

假设我们在页面里面请求m个SSI,而upstream server的最大支撑请求数为n, 且m > n, 这个时候会发生什么事?

我们按照下面的表格对服务进行改造

请求数 server-side include file upstream max connection
1 10 3

如上面的请求,我们在一个父文件里面设置10个ssi,而upstream服务我们设置限流3个请求,请求父文件之后看看会发生什么:

在html文件上设置多个SSI片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello world!</h1>
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
<!--#include virtual="./block.html" -->
</body>
</html>

对upstream server增加限流逻辑,使得SSI请求触发限流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 我们在node服务里面进行一个限流
const ratelimit = require('koa-ratelimit');
const db = new Map();
const app = new Koa();
app.use(logger())

app.use(ratelimit({
driver: 'memory',
db: db,
duration: 10000,
errorMessage: 'Oops! 你被限流了!',
id: (ctx) => ctx.ip,
headers: {
remaining: 'Rate-Limit-Remaining',
reset: 'Rate-Limit-Reset',
total: 'Rate-Limit-Total'
},
max: 3,
}));

响应结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
HTTP/1.1 200 OK
Server: openresty/1.21.4.1
Date: Mon, 24 Jun 2024 12:07:27 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Rate-Limit-Remaining: 2
Rate-Limit-Reset: 1719230857.668981
Rate-Limit-Total: 3
Cache-Control: max-age=0

<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello world!</h1>
<div>ssi from block content</div>
<div>ssi from block content</div>
<div>ssi from block content</div>
<div>ssi from block content</div>
<div>ssi from block content</div>
Oops! 你被限流了!
Oops! 你被限流了!
Oops! 你被限流了!
Oops! 你被限流了!
Oops! 你被限流了!
</body>
</html>%

小结

使用SSI 会对源站请求的数量放大,对源站产生更大的压力挑战

同一个请求, SSI subrequest是并行还是串行的

有没有发现,上述的SSI subrequest ,前面的请求都是好的,而被限流的ssi subrequest ,都是排在后面。

这里我们有个疑问:SSI的请求是串行的吗?

其实从前文worker connection限制来看,这个行为应该是倾向于并行请求。如果是串行请求的话,那么worker connection应该没有那么容易就消耗完。我们推测:

  1. 先请求完父请求
  2. 解析html之后,收集所有的子请求
  3. 并行所有的子请求。

上面仅仅只是猜测,真实情况下,到底是并行请求,还是串行请求,还是要实验了才知道。

设计实验

对于我们的node server,我们进行如下改造,设置动态路由

1
2
3
4
5
6
7
8
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

router.get('/dynamic/sleep/:time', async (ctx) => {
const { time } = ctx.params;
await sleep(time);
ctx.type = 'text/html';
ctx.body = `Hello, world! your path is /dynamic/sleep/${time}`;
})

如果请求upstream 服务,/dynamic/sleep/1000 则会等待1s才响应,/dynamic/sleep/2000 则是2s才响应

接着设置我们的主html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello world!</h1>
<!--#include virtual="/dynamic/sleep/10000" -->
<!--#include virtual="/dynamic/sleep/8000" -->
<!--#include virtual="/dynamic/sleep/5000" -->
</body>
</html>

如果请求index.html文件,则会解析到3个server-side include file, 3个子请求加载时间分别为10s, 8s, 5s.

如果是串行,那么时间应超过 10 + 8 + 5 = 23s;
如果是并行,时间应该接近10s

请求页面,我们看看会发生什么
在浏览器请求的timelime上我们可以很清楚的看到,请求的时间约为10s

在node server的日志

1
2
3
4
5
6
7
8
<-- GET /html/index.html
--> GET /html/index.html 200 15ms 271b
<-- GET /dynamic/sleep/10000
<-- GET /dynamic/sleep/8000
<-- GET /dynamic/sleep/5000
--> GET /dynamic/sleep/5000 200 5,002ms 46b
--> GET /dynamic/sleep/8000 200 8,003ms 46b
--> GET /dynamic/sleep/10000 200 10s 47b

我们可以看到:

  1. 服务端接受到了父请求, 并成功响应
  2. 同时接受到了3个子请求,并按照响应时间先后返回

小结

所以,我们可以得出以下结论

  1. subrequest 是并发请求的
  2. 即使是并发请求,子请求也会按照引入的顺序从先到后进行请求。

总结

SSI在实际应用中可以帮我们解决一些页面内容共用的问题,但是

  1. SSI技术会让用户得到请求的时间更长(父请求时间 + 页面解析时间 + SSI 请求时间 )
  2. SSI subrequest会占用worker connection数量,需要我们对代理服务器的worker数量进行合理评估
  3. 采用SSI 技术,也会对upstream server带来成倍以上的压力挑战

总而言之, SSI是一把双刃剑,在带给我们便利的同时,也要谨慎使用!

4月

买车记

买了一辆车,其实现在感觉不怎么需要,因为出行周边的交通比较发达的。眼看摇到号半年的有效期快到了,最终决定还是买一下吧。也没怎么花时间在挑车上,最终买了丰田的亚洲龙,销售环节基本是妹夫帮忙电话谈的。当时人在老家,跟深圳的4S通了电话,问了两三家可以开到多少,如果合适的话就上深圳提车。可能这里给4S有“外地的单,赚一单是一单”的感觉,价格比在老家便宜了不少,最终直接全款拿下。

家人的身体健康

事情的起因是母亲过年的时候感冒之后就一直在咳嗽,拖了很久之后在老家拍了片子,发现双肺肺炎,于是治疗。等到好了以后去复查,CT提示有结节,并且在结论里面写可有可能的是原位Ca(Ca即是 Cancer,也就是癌症。一些医院为了不引起病人的恐慌,特地写了Ca)。
看到这情况,果断安排了广州的检查,心里想着可能是病症的早期,到时候可能要做个手术活检定性。
好在最终重新做了增强CT结果是没有什么问题,而老家那里说是照CT的机子有点旧可能不是很准(这都行)。

那几天着实有些担心,幸好最终结果是很好,把时间线捋了出来,这些年经历下来,感觉健康真的是太重要了

时间 要点 地点 内容 经验说明
2024过年前至2024-3月 过年期间 - 1、期间一直咳嗽
2、偶尔有盗汗现象
2024/3/12 治疗前CT检查,双肺肺炎 潮州市人民医院 1、左侧第6肋骨骨折并骨痂生长
2、双肺感染
3、扫级肝右叶囊肿
2024/4/17 肺炎后复查CT, 发现结节 潮州市人民医院 右肺上叶尖端磨玻璃结节
2024/4/22 网上云诊室内问诊 广州中肿 约不到想看的医生的号;在网上云诊室问诊,直接开了检查 1、一般来说到医院的第一次问诊,医生都会开具一些检查,特别是一些权威的医院都不相信外院检查,所以第一次问诊网上问诊的话,还是比较省时省力
2、后续发现开了2项增强1项平扫(结果检查当天重新开)
2024/4/26 检查,当天赴广州做检查 广州中肿 1、上午抽血2、下午增强CT(三项检查,胸腔、上腹、颈部) 1、抽血可以约早一点的号,然后到了随时可以抽血
2、上午提前去询问,幸好前台留意到检查单上腹只开的是普通平扫(没有增强)其他两项都是增强,说必须三个都是增强才能做
3、增强空腹2小时以上
2024-04-28 & 29 增强CT报告结果出来 & 云诊室 - 报告提示都是很小的磨玻璃结节影(4mm x 4mm)
云诊室问诊:医生说什么大问题,定期检查就好

运动

运动打卡日: 11/30
跑步km: 50/50

读书

书名 进度
李光耀观天下 50%
十八岁出门远行 5%
疯狂的尿酸 10%
控糖革命 10%
这就是chatGPT 100%
癌症·真相 10%

背景

2024-03-29晚上使用vs code, 发现我的copilot一直不起作用了。

分析

一开始想着可能我配置错了,尝试了各种方法,都不行:

  1. 切换更早版本的copilot(一年前的版本)
  2. 换一台笔记本
  3. 用其他的IDE

copliot 的终端报错显示

1
2
[INFO] [auth] [2024-03-29T14:22:41.063Z] Invalid copilot token: missing token: 403 
[ERROR] [default] [2024-03-29T14:22:41.065Z] GitHub Copilot could not connect to server. Extension activation failed: "Contact Support. You are currently logged in as derycktse."

琢磨了一下看着像是被封了

处理

于是在官网找到客服提ticket实锤被封。
GitHub回复检测我的账号有部署服务的嫌疑,不能解禁。
img
因为我在公司使用了,而公司出口IP走的腾讯云。于是被github 的安全机制扫描出来给封禁了。

于是我质疑他们只看来源不看使用量的策略,毕竟我个人使用的话,这个量还是微乎其微的。
img
最终客服成功给我解封了

3月

整一个3月还是比较忙的,毕竟整个3月是公司的一个季度考核末期,所以本着deadline 是第一生产力的原则,大伙都在冲刺。加上3月也病了一场,所以回顾了一下,3月份并没有做太多的事情。

运动

3月中上旬一直在咳嗽,运动从过年后也歇息有一段时间了。到了中下旬咳嗽才好了,于是恢复了跑步。整体运动量:
运动打卡日: 6/31
跑步km: 30/50

读书

书名 进度
十分钟冥想 100%
洋盘 100%
我的母亲做保洁 100%
前端工程化:体系设计与实践 100%
皮囊 100%
阿里人的答案书 100%
月光落在左手上 20%
暮色将尽 10%
35岁后, 我无路可退? 30%

主要流程

出于安全的考虑,目前在微信小程序端,是无法直接拿到用户的手机号。需要几步安全校验。整体流程大概是:

  1. 在微信后台生成appid & secret
  2. 用户登录微信小程序授权访问手机号,获得手机号获取凭证code
  3. 调取使用appid & secret,获得接口调用凭证 access_token
  4. 使用接口调用凭证 access_token 与手机号获取凭证code调用微信服务获得用户手机号信息
    简单讲即:用户授权 & 调用两次微信服务

小程序端

使用微信的内置组件 <button/>,设置open-type 的值设置为 getPhoneNumber, 当用户点击并同意之后,通过 bindgetphonenumber 事件获取回调信息;
代码如:

1
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
1
2
3
4
5
6
7
8
Page({
getPhoneNumber (e) {
console.log(e.detail.code) // 动态令牌
console.log(e.detail.errMsg) // 回调信息(成功失败都会返回)
console.log(e.detail.errno) // 错误码(失败时返回)
}
})

获取用户小程序服务端流程如下

sequenceDiagram
    participant user as 微信小程序客户端
    participant api as 后端服务
    participant wechat as 微信服务
    user->>api: 授权手机号获取凭证code
    rect rgb(255, 255, 200)
    api->>wechat: ask access_token
    wechat->>api: access_token
    end
    rect rgb(255, 150, 230)
    api->>wechat: access_token
手机号获取凭证code wechat->>api: 用户手机号信息 end

其他

在开发微信小程序过程中,我们可能需要涉及到以下相关的凭证

生成 作用 如何获得 过期时间 执行端
appid 与微信服务交互的凭证 管理后台生成 永久 微信开发者管理后台
secret 与微信服务交互的凭证 管理后台生成 永久(如果不在后台重建) 微信开发者管理后台
手机号获取凭证code 加密后的手机号 用户授权后可以拿到 一次性,被拿去校验成功之后就失效 小程序
接口调用凭据 access token 用来解密手机号code以此获得手机号 通过appid与secret调微信的接口拿到 获取2h后失效,期间都可以使用 服务端
登录凭证 code 跟微信服务获取openid 每次登录的时候 一次性,被拿去校验成功之后就失效 小程序
openid 使用 login code拿到,用户的唯一身份 无法直接获取 永久 服务端

参考

这一两年一直在obsidian记录东西,感觉非常不错。不过有一个问题就是,如果只是一味的记录给自己看,可能失去了和别人交流的机会。考虑到这个层面,还是决定以后得多写一些博客。记录自己在生活以及学习上的一些所得所悟,如果能有人看到我的文字有所共鸣或者收获,那将是非常有意义的事情。
考虑到博客使用hexo 生成,托管在github page 上,hexo有自己的一套文件夹命名格式,我还是比较喜欢在obsidian里面写东西。所以最简单的办法就是在obsidian里面写好文章直接同步到hexo 文件夹里面就行.

目前我的obsidian跟hexo文件夹的位置大概是这样:

my note folder
obsidian ~/my-obsidian-folder/blog/_posts/
hexo blog ~/my-hexo-folder/myname.github.io/source/_posts/

每次写完之后,直接使用rsync 同步一下我的文件夹,再部署到github page 上即可

1
2
rsync -r --delete ~/my-obsidian-folder/blog/_posts/ ~/my-hexo-folder/myname.github.io/source/_posts/
hexo clean && hexo g && hexo deploy

当然还有很多更好的办法,比如使用软链等形式,不过觉得现在这个阶段已经够用了。毕竟写blog的频率当下还达不到非常高频。还是先让自己培养多写作的习惯,等习惯养成之后再进一步优化。

来自2024-08-17 补充,发现每次rsync后,未修改个文件,同样也被重新覆盖了,这里体现在文件的修改时间上,自然而然想到可以使用对比摘要不同再同步的方法,发现rsync已经有参数支持。可以基于摘要进行比对后再决定是否更新

1
-c, --checksum              skip based on checksum, not mod-time & size

修改版

1
rsync -r --checksum --delete ~/my-obsidian-folder/blog/_posts/ ~/my-hexo-folder/myname.github.io/source/_posts/

关于“双拼输入法” 其实很早就听过了,只不过之前一直没去了解它是什么。记得以前用电脑打字,有时候会不小心将输入法切换到了双拼,因为不知道双拼输入法到底是怎么运作的,所以一下子就不会打字了。

年前刷博客的时候无意看到有博主在极力推荐双拼输入法,称其大提高了打字的效率。
作为一个追求效率的人,我对能提升效率的事情都是很感兴趣的。日常的工作交流也经常需要去打字,提升一下打字效率也是一件很有收益的事情。

趁着过年期间,抽空学了一下双拼输入法,现在已经将日常输入法切到了双拼输入法了。

什么是双拼输入法

双拼是一种基于拼音的输入法。拼音的发音可以简单分由声母和韵母组成。
比如 买(m ǎi )、卖(m ài)。

所有的声母和韵母都在键盘上对应一个按键。这样一来,任意一个汉字都可以用两个按键来定位,从而提升打字的速度。

举个例子,“梦想”这个词,全拼需要敲键盘9次,而双拼只需要敲4次,这就是双拼提高打字效率的关键之处。

  • 全拼输入法: mengxiang
  • 双拼输入法:mgxl (基于小鹤方案)

如何上手

双拼输入法有好几种方案,主要的区别就是键位不同而已。
我选择的是小鹤双拼的方案,为什么选择这个方案。主要原因有两点:

  1. 小鹤方案把音节都放在了字母键上,规避了符号按键(有一些双拼方案使用了”;” 这个按键),使得我们能记住更少的键位。
  2. 小鹤双拼把使用频率较高的声韵母放在了比较易于发力的食指和中指上(我个人的小指不是很灵活)

学的过程还是比较顺利的,对着键位,我尝试着把它们记下来。这里分享一个个人小技巧:把每一个按键选一个比较熟悉的汉字作为代表来记。甚至你可以代入你熟悉的人,这样的话你会更容易记得每一个字的位置。
举例

  • Q键:q + iu = 球
  • W键:w + ei = 喂
  • P键:p + ie = 撇
  • Z键:z + ou = 走
  • R键:r + uan = 软
  • M键:m + ian = 棉

只需要在心里将熟悉的字与按键对应并记下来,后续如果打其他的字,只需要将我们熟悉的字单独摘出来声母与韵母组成我们需要的字即可。一般我打字都是按词来打,结合着输入法的联想,大部分情况下都能直接联想到我需要的词。

记住了按键之后,我们只需要多加练习即可,这里推荐一个在线练习网站: https://api.ihint.me/shuang/

当然了,切换输入法总会有一段时间的不应期,因为之前的输入法已经让我们形成了肌肉记忆。但是,一旦你习惯了一个字只需要按两个键就能定位到,那么双拼的好处就会显现出来,打字速度也会逐渐提高。

我们可以在日常的练习中熟能生巧,找我们的朋友聊聊天拉拉家常,写写日记,只要练习多了,形成肌肉记忆,打字速度自然就会提高。

总结

从全拼切换到双拼虽然需要一段适应时间,但总体来说并不太难,只需要记得声母和韵母的位置在哪里,剩下的就是花时间熟悉。
目前虽然打字还谈不上飞快,但基本上来说已经够用了,后续如果习惯了速度也会进一步提升上来。
有意思的是,切换输入法后,和别人聊天会有一种重新组织语言的感觉,好像讲话的风格都不是原来自己的样子。
当然了,目前的输入法基本都具备了强大的联想能力,其实使用全拼的速度对大部分人来说已经够用了。

参考