KV Cache 是一个基于 Serverless API 的键值对存储系统,能将数据库操作转化为 HTTP 请求,为联网项目提供便捷的非关系型数据库服务。文章详细介绍了该项目的安全机制(如 UUID 防扫、密码保护、IP 白名单)、API 接口的使用方法以及在 Vercel 上的部署流程,最后还分享了一个利用 404 机制实现的在线剪切板前端案例。
LOADING...
KV Cache 是一个基于 Serverless API 的键值对存储系统,能将数据库操作转化为 HTTP 请求,为联网项目提供便捷的非关系型数据库服务。文章详细介绍了该项目的安全机制(如 UUID 防扫、密码保护、IP 白名单)、API 接口的使用方法以及在 Vercel 上的部署流程,最后还分享了一个利用 404 机制实现的在线剪切板前端案例。
KV Cache是我去年11月写的一个KV存储的实践项目,功能很简单——把对数据库的各种操作转为Serverless API,你也可以认为这是一个可基于http请求进行操作的数据库。
项目地址:RavelloH/kv-cache: 基于 api 进行操作的缓存系统
随后,我又写了个网页用来快速操作数据库,类似于note.ms,可以把它当成是一个在线剪切板,非常适合在多个设备之前轻松传递文字内容。不过实现的方式比较邪道,这只是个404.html,所以理论上部署在哪都行,这也算一种前后端分离吧(笑)
项目地址:RavelloH/kv-clipboard: 使用 kv-cache 项目为存储的在线剪切板前端
下面主要介绍的是KV Cache,前端那个结尾稍微提一下。
因为有网就能访问Serverless API,就能操作数据库,所以你可以轻松的为你的任何能连网的项目增加一个非关系型数据库,同时也遵循KV数据库这样的键值对形式存储规则。不过在此项目中,为了确保各个数据独立安全,你需要使用uuid作为键名。
作为数据库首先需要保障内容的安全,虽然本项目是在KV数据库里明文存储你的内容的,不过在读取和写入的实现上做了很多安全保障。具体来说:
直接发送POST请求就能跟数据库交互了,方便。
作为一个Serverless项目可以轻松部署在各大云平台上。推荐使用Vercel,因为它会直接送你KV数据库。
下面直接贴Github上面的文档了,毕竟这个项目也不会更新了,文档不会变动的
此API提供了数据的读写和删除功能。请求方法包括POST和GET。
/api?mode=set或/set请求数据有两种方法,可以以POST的方式请求,返回json格式的数据,或者以GET的方式请求,返回文本格式的数据
/api?mode=get或/get/api 或 /https://cache.ravelloh.top/?uuid=xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx&password=123456&shouldDelete=true/api?mode=del或/del/api写入数据:
读取数据:
删除数据:
部署很轻松,实际上可以使用Vercel一键部署。
转到你的Vercel,在此页面中创建一个KV Database. vercel/stores尽量选择离你更近的服务地区,名称随意。如果切换了服务地区,你可稍后在下方的部署按钮部署结束后,在项目设置中更改你的项目serverless地区为服务器所在地区以提高性能。转到你的数据库页面,切换至,如图。记录如下两项的值:
image.png
之后,单击下方部署按钮,填入上方值即可一键部署。
Deploy with Vercel
image.png
(后面改版成这样了)
图片
访问进去你会发现自己被重定向到了https://clip.ravelloh.top/xxxx,其实这里我随便写了个算法把任意字符串转为UUID,所以那个xxxx你可以随便输。算法我感觉挺满意的,放下面了。
除此之外前端部分就没什么技术含量了,直接调用API就是。另外值得一提的是这个页面的实现方式,实际上你访问到的所有页面都是404.html,因为本来也没东西,所以会转到404,之后读取一下当前页面的地址直接转成UUID,跟KV Cache要数据就行。这些是我之前只会静态站的时候想到的歪门邪道的办法,我当时美其名曰“伪动态”,反正效果是达到了。
.env.localKV_REST_API_TOKENKV_REST_API_URLfetch('https://cache.ravelloh.top/api?mode=set', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
data: 'Hello, World!',
password: '123456',
safeIP: '*.*.*.*',
expiredTime: 24 * 60 * 60 * 1000,
uuid: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));fetch('https://cache.ravelloh.top/api?mode=get', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
uuid: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',
password: '123456',
shouldDelete: false
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));fetch('https://cache.ravelloh.top/api?mode=del', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
uuid: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));async function stringToUUID(str) {
const encoder = new TextEncoder();
const data = encoder.encode(str);
// 使用SHA-1哈希函数进行哈希处理
const hashBuffer = await crypto.subtle.digest("SHA-1", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
// 将哈希值转换为16进制字符串
const hashHex = hashArray
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
// 将哈希值转换为UUID格式
const uuid = [
hashHex.substring(0, 8),
hashHex.substring(8, 12),
hashHex.substring(12, 16),
hashHex.substring(16, 20),
// 截取20到32位,并设置版本和变体位
hashHex.substring(20, 24) +
"4" + // 设置版本为4
hashHex.substring(24, 36), // 变体位10xx
].join("-");
return uuid;
}
评论