首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Cloudflare D1 - 免费数据存储

编程知识
2024年09月09日 13:03

前言

自从上次将博客项目的图片从 七牛云 迁到了 Cloudflare R2 之后就发现,Cloudflare 这个赛博菩萨的产品是真的不错,非常的适合白嫖,DevNow 项目作为一个开源博客,整体来说是希望越少依赖一些服务越好,使整个构建、部署流程更加的 轻便 和 快捷 ,让对于前端不是很熟的同学也能快速的搭建一个自己的博客。

这篇文章其实完全是个人爱好,只要是实现如何集成 Cloudflare D1 来给文章详情页增加一个浏览量。目前还没想好是否要往 DevNow 项目上同步这个功能,就现在自己的 blog 上试试水,如果大家有需求的话,后边在看是不是可以写一个脚本集成到 DevNow 项目中。

方案

方案整体来说是很多的,这里简单说下我考量的一些因素:

  • 自己有服务器,可以自己搭建一个数据库实现。
  • 通过一些比较成熟的数据存储服务,可能需要订阅功能。
  • 借助类似 CloudflareVercel 这样的服务商上的一些服务来实现,数据量少的话就是白嫖。severless 的实现方案对前端来说也比较友好。

这里还有一个考量是后续可能会考虑通过 Cloudflare Page 部署前端的方案,完全从 Vercel 切到 Cloudflare,减少多个服务商带来的管理和集成的复杂度。

先简单介绍一些 Cloudflare D1 ;

官方的介绍:
使用 D1 短短数秒内即可创建一个无服务器的关系数据库。通过熟悉的查询语言、时间点恢复功能和经济实惠的定价,赋能您构建下一个重大项目。

方案

其实这里主要看 Free 版的服务,这里其实有两个服务可以选择, KVD1 都可以用来存储数据,这里选择 D1 主要考量因素就是 KV 的每日写入操作只有 1000 次,整理来对于一些好的博客网站可能会超过,所以直接上 D1

集成到 DevNow 项目中

:::tip[注意]

整体来说所有的操作都有两种实现方式,一个是在 Cloudflare D1 的官网里边操作,一个是通过命令行来实现。

我这里主要记录一下命令行的实现,通过一些命令和代码来创建和部署 D1 的服务,可以更好的理解整个的流程。

前置条件 :已经完成 Cloudflare 账号的注册和信用卡💳的绑定,否则无法后续的流程

:::

参考文档:Cloudflare D1

1. 创建一个Worker

pnpm create cloudflare@latest d1-tutorial
// d1-tutorial 是 <WORDER_NAME>

对于设置,请选择以下选项:

  • For What would you like to start with? choose Hello World example.
  • For Which template would you like to use? choose Hello World Worker.
  • For Which language do you want to use? choose TypeScript.
  • For Do you want to use git for version control? choose Yes.
  • For Do you want to deploy your application? choose No (we will be making some changes before deploying).

然后项目中将会得到以下的一个目录。

D1 floder

2. 创建数据库

D1 数据库在概念上与许多其他数据库类似:数据库可能包含一个或多个表、查询这些表的能力以及可选索引。 D1 使用熟悉的SQL 查询语言↗ (与 SQLite 使用的一样)。

切换到您刚刚为 Workers 项目创建的目录:

cd d1-tutorial

运行以下命令并为您的数据库命名。在本教程中,数据库名为 devnow

npx wrangler d1 create devnow


# 然后会输出以下内容:
# [[d1 databases]]
# binding ="DB" # available in your Worker on env.DB
# database name ="prod-d1-tutorial"
# database id ="<unigue-ID-for-your-database>"

这将创建一个新的 D1 数据库并输出下一步所需的绑定配置。

wrangler命令行界面是 Cloudflare 的工具,用于在终端中管理和部署 Workers 应用程序和 D1 数据库。它是在您使用npm create cloudflare@latest初始化新项目时安装的。

3. 将 Worker 绑定到您的 D1 数据库

您必须为 Worker 创建绑定才能连接到 D1 数据库。绑定允许您的 Workers 访问 Cloudflare 开发者平台上的资源,例如 D1。您可以通过更新wrangler.toml文件来创建绑定。

复制第二步输出的结果到 wrangler.toml 文件中。

[[d1_databases]]
binding = "DB" # available in your Worker on env.DB
database_name = "prod-d1-tutorial"
database_id = "<unique-ID-for-your-database>"

到这里一个本地的 D1 数据库就建好了

4. 对 D1 数据库进行查询

4.1 更新 schema.sql 文件:

// d1-turorial/schema.sql

DROP TABLE IF EXISTS PageView;
CREATE TABLE IF NOT EXISTS PageView (
	PageId INTEGER PRIMARY KEY AUTOINCREMENT,
	Path TEXT UNIQUE NOT NULL,
	Count INTEGER,
	LastVisited INTEGER
);
INSERT INTO PageView (PageId, Path, Count, LastVisited)
VALUES
(1, '/posts/1', 0, 1725673703),
(2, '/posts/2', 0, 1725673703),
(3, '/posts/3', 0, 1725673703);

4.2 初始化数本地据库

npx wrangler d1 execute devnow --local --file=./schema.sql

4.3 验证数据是否在数据库中

npx wrangler d1 execute devnow --local --command="SELECT * FROM PageView"

看到如下图结果,即表示本地数据库创建成功:

D1 sql result

5 在 Worker 中编写查询方法

这里实现了根据 /d1/pageview/ 来请求,然后 获取更新 页面数据的接口。

// page: d1-tutorial/src/index.ts

export interface Env {
  DB: D1Database;
}

export default {
  async fetch(request, env): Promise<Response> {
    const url = new URL(request.url);
    const pathname = url.pathname; // 获取页面路径

    // 检查是否以 https://d1.laughingzhu.cn/d1/pageview 开头
    if (!pathname.startsWith('/api/pageview')) {
      return new Response('Not Found', { status: 404 });
    }

    // 继续处理 https://d1.laughingzhu.cn/d1/pageview 路径下的请求
    const trimmedPath = pathname.replace('/api/pageview/', '/'); // 去除开头部分,获取具体页面路径
    if (request.method === 'GET') {
      try {
        // 查询指定 path 的浏览量
        const result = await env.DB.prepare(`SELECT Count FROM PageView WHERE Path = ?`)
          .bind(trimmedPath)
          .first();

        // 如果没有记录,返回 0
        const count = result ? result.Count : 0;
        return new Response(JSON.stringify({ path: trimmedPath, count }), {
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error: any) {
        console.error('Database operation failed:', error);
        return new Response(`Failed to fetch page views for ${trimmedPath}: ${error.message}`, {
          status: 500
        });
      }
    }
    if (request.method === 'POST') {
      // 使用 UPSERT 来尝试更新 count,如果没有该页面则插入新的记录
      try {
        // UTC 转成北京时间
        const utcTimestamp = Math.floor(Date.now() / 1000);
        const { results } = await env.DB.prepare(
          `
            INSERT INTO PageView (Path, Count, LastVisited)
            VALUES (?, 1, ?)
            ON CONFLICT(Path)
            DO UPDATE SET Count = Count + 1, LastVisited = ?
          `
        )
          .bind(trimmedPath, utcTimestamp, utcTimestamp)
          .run();
        // return Response.json(results);
        if (results) {
          return Response.json({
            message: `Page views for ${trimmedPath} updated.`,
            data: results
          });
        } else {
          return new Response(`Page views for ${trimmedPath} updated, but no results returned.`, {
            status: 200
          });
        }
      } catch (error: any) {
        console.log(error);
        return new Response(`Failed to update page views for ${trimmedPath}: ${error.message}`, {
          status: 500
        });
      }
    }

    // 如果是其他方法,不允许操作
    return new Response('Method Not Allowed', { status: 405 });
  }
} satisfies ExportedHandler<Env>;

配置 Worker 后,您可以在全局部署之前在本地测试您的项目。

6. 本地开发运行 Worker

npx wrangler dev

当您运行 wrangler dev 时,Wrangler 会提供一个 URL(很可能是 localhost:8787)来查看您的 Worker。

示例:

我们通过浏览器访问 http://localhost:8787/d1/pageview/posts/hello-word

get result

查询返回以下数据,这是因为数据库中没有,默认是0。

到这里本地调试就完事了。

7.部署线上 D1 数据库

创建远程线上数据库:

npx wrangler d1 execute devnow --remote --file=./schema.sql

查询远程线上数据库:

npx wrangler d1 execute prod-d1-tutorial --remote --command="SELECT * FROM Customers"

这里和步骤 4.2 、 4.3 的区别就是 --local 换成了 --remote .

7.1 部署 worker 方法

npx wrangler deploy

这里主要是部署我们在 worker 中实现的方法,不如上述步骤 4.4 在 d1-turorial/src/index 中实现的查询、更新页面数据的方法。

到这里就可以整个 wokrer 和 数据库就部署完成了,我们可以到线上去看一下。

online table

我们可以看到 Cloudflare 给我们提供了默认的 Worker 的访问路由,为了方便,我们也可以添加一个自定义路由,通过自定义路由访问,如下。

worker way

到这里整个 Cloudflare D1 数据库这里就接入完成了。

接下来我们在前端项目中来增加相关的请求方法。

DevNow 前端项目中增加查询、更新浏览量方法

1. 实现方案:

整体来说这里由于期望 浏览量 这个数据比较实时,所以大概方案我能想到的是两种方案:

  • CSR 去做,可以通过集成 React 来实现在运行时去请求 api 来完成(最简单);
  • 渲染方案从 SSG 切换到 SSR ,这样页面会在每次访问的时候在服务端动态的生成,数据可以保持实时。(这里遇到一些坑,下边会提)

最终我选择了 SSR 方案,主要考量的因素如下:

使用 CSR 运行时请求会导致接口暴露,由于没有用户身份体系,很容易让一些无聊的人刷接口,主要我们白嫖每天是限额,超出是要收钱的。

所以这里采用了 SSR 的方案,这样就可以不暴露接口来实现,不过这里可能会牺牲掉 SSG 带来的更好缓存效果。

这里主要是删除、替换适用于 SSG 方案中的一些 API :

// page: src/posts/[...slug].astro

// 删除  export const prerender = true;

// 删除 getStaticPaths() 相关方法
//可以通过 getEntry 来获取对应的文章内容

import { getEntry } from 'astro:content';
const { slug } = Astro.params;
const post = await getEntry('doc', slug);

2. Astro 中如何接入

开始使用了 Astro 提供的 API 端点 ,后来仔细了解完这个是 SSG 的方案,之后在构建的时候请求,后边就不会走了,所以基于 API 端点 的实现方式 PASS

其实 Astro 中 数据请求 的文档中有提到,可以使用 Fetch 来实现。

官网关于 fetch 的

fetch 调用将会在构建时执行,并且数据都可用于组件模板中来生成动态 HTML。如果启用 SSR 模式,任何 fetch 调用都将在运行时执行。

// page: src/posts/[...slug].astro
//增加如下来实现动态获取访问量

const { slug } = Astro.params;
const data = await fetch(`https://xxx.d1.hosts/d1/pageview/posts/${slug}`);
const result = await data.json();

这里可以提出到一个指定的文件来维护,示例我就不改了。

优化空间:只有在线上环境才请求,线上不请求,来增加数据的准确度。

更新的实现同上。

3. 页面缓存的问题

部署到线上环境时发现个问题,只有部署完第一次访问会增加请求对应的方法,后边就不请求了,猜测是 Vercel 这边有缓存,然后在 Response 体里看到了 x-vercel-cache: HIT 。第一次是 MISS 以后所有的都是 HIT ,这里其实可以理解成部署完第一次访问的时候 Vercel 帮我们生成了一份缓存,后续所有的人访问都走的是缓存,这样在速度上就会有更好的体验,本来是个好东西,还给我卡主了。

然后就各种开始找方法来避免缓存生效。给请求加 禁止缓存字段,给 vercel.json header 增加对应路由不缓存的配置发现都没有用。

这里可以通过开启 D1 的实时日志来调试:

实时日志

然后突然想到会不会是 ISR 导致的问题,之前默认打开了,搜索了一会发现,ISR 模式会自动缓存我们的文件。解决方案就是 将 astro.config.js 中的 ISR 配置删除即可。

完事,到这里项目里就可以展示 浏览量了。效果图如下:

效果图

原文链接:Cloudflare D1 - 免费数据存储

From:https://www.cnblogs.com/LaughingZhu/p/18404419
本文地址: http://shuzixingkong.net/article/1854
0评论
提交 加载更多评论
其他文章 KernelWarehouse:英特尔开源轻量级涨点神器,动态卷积核突破100+ | ICML 2024
动态卷积学习n个静态卷积核的线性混合,加权使用它们输入相关的注意力,表现出比普通卷积更优越的性能。然而,它将卷积参数的数量增加了n倍,因此并不是参数高效的。这导致不能探索n&gt;100的设置(比典型设置n&lt;10大一个数量级),推动动态卷积性能边界提升的同时享受参数的高效性。为此,论文提出了K
KernelWarehouse:英特尔开源轻量级涨点神器,动态卷积核突破100+ | ICML 2024 KernelWarehouse:英特尔开源轻量级涨点神器,动态卷积核突破100+ | ICML 2024 KernelWarehouse:英特尔开源轻量级涨点神器,动态卷积核突破100+ | ICML 2024
tarjan—算法的神(一)
本篇包含 tarjan 求强连通分量、边双连通分量、割点 部分, tarjan 求点双连通分量、桥(割边)在下一篇。 伟大的 Robert Tarjan 创造了众多被人们所熟知的算法及数据结构,最著名的如:(本文的)连通性相关的 tarjan 算法,Splay-Tree,Toptree,tarjan
tarjan—算法的神(一) tarjan—算法的神(一) tarjan—算法的神(一)
超轻量级、支持插件的 .NET 网络通信框架
前言 给大家推荐一个轻量级的、支持插件的综合网络通信库:TouchSocket。 TouchSocket 的基础通信功能包括 TCP、UDP、SSL、RPC 和 HTTP。其中,HTTP 服务器支持 WebSocket、静态网页、XML-RPC、WebAPI 和 JSON-RPC 等扩展插件。 此外
超轻量级、支持插件的 .NET 网络通信框架 超轻量级、支持插件的 .NET 网络通信框架 超轻量级、支持插件的 .NET 网络通信框架
基于Service Worker实现WebRTC局域网大文件传输能力
基于Service Worker实现WebRTC局域网大文件传输能力 Service Worker是一种驻留在用户浏览器后台的脚本,能够拦截和处理网络请求,从而实现丰富的离线体验、缓存管理和网络效率优化。请求拦截是其关键功能之一,通过监听fetch事件,Service Worker可以捕获所有向网络
Python将表格文件中某些列的数据整体向上移动一行
本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,对其中的每一个文件加以操作——将其中指定的若干列的数据部分都向上移动一行,并将所有操作完毕的Excel表格文件中的数据加以合并,生成一个新的Excel文件的方法~
Python将表格文件中某些列的数据整体向上移动一行
秋天希望的田野,九月最后的救园:终身会员计划
在7月15日发出求救信后快2个月了,很多园友出手相救——买会员、买周边、献捐助、送赞助,让救园走在希望的田野上,非常感谢每一位出手相救的园友! 在这救园期间,很多园友提出了很多很好的商业化与发展建议,我们会结合园子的实际情况与发展进展,参考大家的建议。 在这救园期间,有投资人过来谈投资,有企业过来谈
秋天希望的田野,九月最后的救园:终身会员计划 秋天希望的田野,九月最后的救园:终身会员计划
生财有迹 | 您专属的资产跟踪与分析工具
生财有迹(Wealth Tracker)是一款专注于个人资产分析的应用程序。其核心功能是:全面记录并展示用户的资产状况,帮助用户轻松了解财务现状;运用 AI 能力,结合每种资产的特性和当前环境,提供适宜的财务建议。
生财有迹 | 您专属的资产跟踪与分析工具 生财有迹 | 您专属的资产跟踪与分析工具 生财有迹 | 您专属的资产跟踪与分析工具
FastGPT 正式接入 Flux,准备好迎接 AI 绘画的狂风了么?
Flux 大家最近都听说了吧?它是一款新推出的 AI 绘画模型,拳打 Stable Diffusion 3,脚踢 Midjourney,整个 AI 绘画界都沸腾了。 Flux 的主创团队来自由 Stable Diffusion 原班人马打造的黑森林实验室 (BlackForestLabs),2024
FastGPT 正式接入 Flux,准备好迎接 AI 绘画的狂风了么? FastGPT 正式接入 Flux,准备好迎接 AI 绘画的狂风了么? FastGPT 正式接入 Flux,准备好迎接 AI 绘画的狂风了么?