折腾/memos
想到了如何通过CF Workers 让新版Memos 兼容广场,以下代码AI生成
新建一个workers
const NEW_ORIGIN = "https://memos.ee";
const KV = MEMOS_MAP; // KV 绑定名
const CORS_HEADERS = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization"
};
/* ---------- 工具:原子自增数字 id ---------- */
async function allocNumericId() {
const val = await KV.get("next_id");
const next = val ? Number(val) + 1 : 10000;
await KV.put("next_id", String(next));
return next;
}
/* ---------- 工具:建立 UID↔数字 双向映射 ---------- */
async function getNumericId(uid) {
let num = await KV.get(`uid:${uid}`);
if (!num) {
num = await allocNumericId();
await KV.put(`uid:${uid}`, String(num));
await KV.put(`num:${num}`, uid);
}
return Number(num);
}
/* ---------- 用户信息内存缓存 ---------- */
const userCache = new Map();
async function fetchUser(uid) {
if (userCache.has(uid)) return userCache.get(uid);
const r = await fetch(`${NEW_ORIGIN}/api/v1/users/${uid}`);
if (!r.ok) return null;
const data = await r.json();
userCache.set(uid, data);
return data;
}
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(req) {
const url = new URL(req.url);
if (req.method === "OPTIONS") {
return new Response(null, { status: 204, headers: CORS_HEADERS });
}
/bin /config /dev /etc /home /lib /media /memos /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var ---------- 旧 /api/v1/memo 兼容 ---------- */
if (url.pathname === "/api/v1/memo") {
const creatorId = url.searchParams.get("creatorId") || "1";
const rowStatus = url.searchParams.get("rowStatus") || "NORMAL";
const limit = Number(url.searchParams.get("limit") || "10");
const offset = Number(url.searchParams.get("offset") || "0");
const need = offset + limit;
const up = new URL("/api/v1/memos", NEW_ORIGIN);
up.searchParams.set("parent", `users/${creatorId}`);
up.searchParams.set("state", rowStatus);
up.searchParams.set("pageSize", Math.min(need, 1000));
const r = await fetch(up, {
headers: { Authorization: req.headers.get("Authorization") || "" }
});
if (!r.ok) return new Response(await r.text(), { status: r.status });
const { memos = [] } = await r.json();
const slice = memos.slice(offset, offset + limit);
/bin /config /dev /etc /home /lib /media /memos /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var 给每条记录分配数字 id 并缓存 */
for (const m of slice) {
const uid = m.name.split("/")[1];
await getNumericId(uid);
}
/bin /config /dev /etc /home /lib /media /memos /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var 读 KV 拿到数字 id */
const uidSet = new Set(slice.map(m => Number(m.creator.split("/")[1])));
await Promise.all([...uidSet].map(uid => fetchUser(uid)));
const legacy = await Promise.all(
slice.map(async m => {
const uid = Number(m.creator.split("/")[1]);
const user = userCache.get(uid);
const num = await getNumericId(m.name.split("/")[1]);
return {
id: num, // ← 数字 id
rowStatus: m.state,
creatorId: uid,
createdTs: Math.floor(new Date(m.createTime).getTime() / 1000),
updatedTs: Math.floor(new Date(m.updateTime).getTime() / 1000),
displayTs: Math.floor(new Date(m.displayTime).getTime() / 1000),
content: m.content,
visibility: m.visibility.toUpperCase(),
pinned: m.pinned,
parent: null,
creatorName: user?.displayName || "",
creatorUsername: user?.username || "",
resourceList: m.attachments || [],
relationList: m.relations || []
};
})
);
return new Response(JSON.stringify(legacy), {
headers: { "content-type": "application/json", ...CORS_HEADERS }
});
}
/bin /config /dev /etc /home /lib /media /memos /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var ---------- /m/ 双向 301 ---------- */
const match = url.pathname.match(/^\/m\/([^/]+)$/);
if (match) {
const slug = match[1];
// 1) 纯数字 → 查 UID
if (/^\d+$/.test(slug)) {
const uid = await KV.get(`num:${slug}`);
if (uid) return Response.redirect(`${NEW_ORIGIN}/memos/${uid}`, 301);
else return new Response("Not Found", { status: 404 });
}
// 2) UID → 查数字并写入 KV
const num = await getNumericId(slug);
return Response.redirect(`${NEW_ORIGIN}/m/${num}`, 301);
}
/bin /config /dev /etc /home /lib /media /memos /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var ---------- 其余全部 301 ---------- */
return Response.redirect(NEW_ORIGIN + url.pathname + url.search, 301);
}
把https://memos.ee更改为自己的memos地址 把代码粘贴进去 点击部署
在KV中新建一个数据库命名空间随便填写
在workers中绑定命名空间 变量名称MEMOS_MAPKV 命名空间选择上面创建好的
最好给workers绑定好域名例如 https://old.memos.ee
使用memobbs 广场演示 https://memobbs.memos.ee