11/12月小结-低谷

2025-01-15

前言

对我个人来说, 这2个月可以说是令我痛苦的2个月了, 有史以来第一次”挂科”.

30%的原因出在语言上, 这门课需要理解题目并分析. 偏理论, 我缺乏这方面的复习经验.另外40%的原因出在我没有给这门课很高的重视, 我的作业成绩很高, 轻视考试的深度和难度了. 剩下30%的原因是我单打独斗了. 我给这门课程留下的预习复习时间是别的课程的的1/10甚至更少.

遭遇失败也不能找借口, 要找原因, 所以这学期打算找学习伙伴, 并且学习重心放在这门课上.

说起来很轻巧, 实际上在整整1个月的假期中 (12.13考完-12.27出这门课的成绩-1.13开学)情绪低落了大半个月, 什么都没有做, 也什么都没有做好. 仿佛回到了本科时候被论文和考研压得喘不过气的日子. 做梦惊醒, 呼吸费劲成为常态… 然后养成了现在每天吃维生素D的习惯.

苦中得乐

谢谢亲人和好友, 在我低落的时候开导我安慰我, 让我不至于一蹶不振. 和好友一起在家吃火锅, 打雪仗, 打游戏. 让我的情绪稳定了很多.

去IGA买了三文鱼, 自己在冰箱冻了半个月来杀死寄生虫. 基于售卖的三文鱼的样子, 我得出了一个结论, 国内的三文鱼都是达不到生食品质的, 均为冷冻杀死寄生虫后再拿出来售卖的, 自己冻会更便宜和健康.

吃完竟然不会拉肚子
吃完竟然不会拉肚子

还有最大的一个改变就是驾驶技术, 飞速增长. Montreal迈入冬季, 一周可能有6天都没有太阳, 在体感温度大约为-15℃的天气还是开车出门购物更合适. 偶尔接上朋友去购物, 经常要跑高速. 争取这学期考下来驾照.

博客装修

从上年年底友邻竹子在Mastodon转发了OpenHeart相关的帖子后我尝试部署了一下. 出现了无法使用的问题, 近日仔细查找后发现提供的worker.js多了一次编码, 导致前端GET和POST的地址和KV中所存储的不一样. 在这里提供一些参考性的建议.

Openheart整个流程为: 前端传递-后端存储-前端获取. 当在前端点赞后, 通过脚本(worker.js)创建键值对(KV)进行存储, 并通过前端js来刷新显示最新的点赞计数. 现在来详细的进行部署.

后端存储

本文教程使用Astro和Cloudflare

首先创建一个存储库: 存储和数据库-KV-创建. 如果想开箱即用, 名字就和我一样设置为KV即可.

接下来创建Cloudflare Workers, 代码为:

const instruction = `.^⋁^.
'. .'
\`
OpenHeart protocol API
`;
export default {
async fetch(request, env) {
if (request.method === 'OPTIONS') {
return new Response(null, { headers });
}
if (request.method === 'GET') {
if (url(request).pathname === '/') {
return new Response(instruction, { headers });
} else {
return handleGet(request, env);
}
}
if (request.method === 'POST') return handlePost(request, env);
},
};
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,POST",
"Access-Control-Max-Age": "86400",
};
function error(text, code = 400) {
return new Response(text, { headers, status: code });
}
function url(request) {
return new URL(request.url);
}
function ensureEmoji(emoji) {
const segments = Array.from(
new Intl.Segmenter({ granularity: 'grapheme' }).segment(emoji.trim())
);
const parsedEmoji = segments.length > 0 ? segments[0].segment : null;
if (/\p{Emoji}/u.test(parsedEmoji)) return parsedEmoji;
}
// Generate KV keys with single encoding
function generateKey(domain, uid, emoji) {
const encodedDomain = encodeURIComponent(domain); // Single encoding
const encodedUid = encodeURIComponent(uid); // Single encoding
return `${encodedDomain}:${encodedUid}:${emoji}`;
}
async function handleGet(request, env) {
const [domain, ...uidParts] = url(request).pathname.slice(1).split('/');
const decodedDomain = decodeURIComponent(domain); // 解码
const decodedUid = decodeURIComponent(uidParts.join('/')); // 解码
const prefix = `${encodeURIComponent(decodedDomain)}:${encodeURIComponent(decodedUid)}`; // 单次编码
console.log("GET Prefix:", prefix); // 调试日志
const res = await env.KV.list({ prefix });
const list = {};
for (const key of res.keys) {
const value = await env.KV.get(key.name);
const [, uidDecoded, emoji] = key.name.split(':').map(decodeURIComponent); // 解码键值
const obj = list[uidDecoded] || {};
obj[emoji] = Number(value);
list[uidDecoded] = obj;
}
console.log("GET Response Data:", list); // 调试日志
return new Response(
JSON.stringify(list[decodedUid] || {}),
{ headers: { ...headers, 'Content-Type': 'application/json;charset=UTF-8' } }
);
}
async function handlePost(request, env) {
const urlObject = url(request);
const path = urlObject.pathname.slice(1);
if (path === '') return error('pathname missing');
const [domain, ...uidParts] = path.split('/');
const decodedDomain = decodeURIComponent(domain); // 解码
const decodedUid = decodeURIComponent(uidParts.join('/')); // 解码
const emoji = ensureEmoji(await request.text());
if (!emoji) return error('request body should contain an emoji');
// Generate the key with single encoding
const key = generateKey(decodedDomain, decodedUid, emoji);
console.log("POST Generated Key:", key); // 调试日志
const currentCount = Number(await env.KV.get(key) || 0);
await env.KV.put(key, currentCount + 1);
return new Response('recorded', { headers });
}

在推送后回到Worker的设置界面, 绑定刚刚创建的KV, 名称均设置为KV. 当我使用自定义域的时候出现了问题, 因此我使用了默认的workers.dev域名.

前端传递/获取

接下来就是前端的传递. 在Openheart的协议中, 你需要在访问API时提供一个target和uid, 这个target可以是任何字符串, 于是我设置为当前博文的链接并将uid默认为like. 所以根据官方的文档, 可以通过以下命令来进行POST(点赞)和GET(获取点赞数)操作:

Terminal window
curl -d '💯' -X POST 'https://xxx.workers.dev/xxx.example.com/like'
recorded%
curl 'https://xxx.workers.dev/xxx.example.com/like'
{"❤️":1}%

在这个过程中, 特殊字符, 例如:/会根据worker.js设置来影响对KV的存储. 因此需要对url编码一次来转换这些特殊字符.

---
// Get current URL dynamically
const currentUrl = Astro.url.toString();
---
<div class="like">
<open-heart href={`https://xxx.workers.dev/${currentUrl}/like`} data-umami-event="Like" emoji="❤️">❤️</open-heart>
</div>

这样的请求和存储就保持一致了, 你可以通过开发者工具来确认这一点

最后就是前端样式, 由于我的基于benji的二次修改, 这是benji的文章链接, 可以自行访问获取.

书影音游

颓废的这段时间都用来看小说了, 重新看了一遍龙族.

第七集的抽帧让我感到惊艳, 就是最后的结尾略显仓促, 杰斯陪葬的动机我感觉不是很清晰.

圣诞时候和大家一起用Switch玩了.

一部不错的魔幻史诗, 在刚出的时候觉得名字好听体验了一下, 被冗长的任务打断了. 现在创新号重新回坑过完了剧情, 很棒.

Random Read