news 2026/8/30 5:02:42

Cloudflare Workers+Pages+D1:构建无服务器边缘应用完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cloudflare Workers+Pages+D1:构建无服务器边缘应用完整方案

Cloudflare Workers+Pages+D1:构建无服务器边缘应用完整方案

本教程通过制作一个简单的“留言板”,学习 Cloudflare 三个核心产品:

  • Cloudflare Pages:部署前端页面
  • Cloudflare Workers:编写后端 API
  • Cloudflare D1:保存留言数据

最终架构:

一、Cloudflare Pages、Workers、D1 分别是什么

组件角色可部署 / 运行内容本项目承担功能
Pages前端静态托管HTML、CSS、JS、Vue、React、静态网站展示留言板标题、姓名输入框、留言输入框、提交按钮、留言列表
Workers边缘后端 API 服务JavaScript / TypeScript,处理 HTTP 请求接口:GET/api/helloGET/api/messagesPOST/api/messagesPOST/api/echo数据校验、读写 D1、返回 JSON、对接 KV/R2
D1边缘 SQLite 数据库SQLite 结构化数据存储(替代传统数据库)存储字段:留言编号、留言人姓名、留言内容、创建时间

二、准备 GitHub 仓库

本教程使用 GitHub 保存代码,并让 Cloudflare 自动部署。需要创建两个仓库:

  • my-worker:保存 Workers 后端代码
  • my-pages:保存 Pages 前端代码

进入 https://github.com/new 两个仓库可以设置为 Public,也可以设置为 Private。

三、创建D1数据库

1、创建数据库

进入**【cloudflare主页】——【存储与数据库】——【D1 SQLite数据库】——【创建数据库】**

创建后记录你的Database nameDatabase UUID

2、创建数据表

进入 D1 数据库的控制台或 SQL 编辑器,执行:

CREATETABLEmessages(idINTEGERPRIMARYKEYAUTOINCREMENT,nameTEXTNOTNULL,messageTEXTNOTNULL,created_atTEXTNOTNULLDEFAULTCURRENT_TIMESTAMP);

创建索引:

CREATEINDEXidx_messages_created_atONmessages(created_at);

插入测试数据:

INSERTINTOmessages(name,message)VALUES('测试用户','这是第一条留言');

查询测试:

SELECT*FROMmessagesORDERBYidDESC;

如果可以查询到数据,说明表创建成功。

四、创建Worker项目

进入 Cloudflare 控制台:【计算】——【Workers 和 Pages】——【创建应用程序】——【Continue with GitHub】

授权 GitHub 后,选择:【my-worker】仓库,如果仓库为空,先在 GitHub 中添加以下文件。

my-worker/ ├── src/ │ └── index.js ├── wrangler.jsonc └── package.json

代码示例:

wrangler.jsonc

{"name":"my-worker",//Worker 名称"main":"src/index.js",//入口文件"compatibility_date":"2026-08-26","d1_databases":[{"binding":"DB","database_name":"my-database",//填写上面的D1数据库名称"database_id":"22d7ad3f-cb4e-4aea-b47f-ae3f30674a28"//填写上面的D1数据库UUID}]}

package.json

{"name":"my-worker","private":true,"version":"1.0.0","devDependencies":{"wrangler":"^4.26.0"}}

index.js

constallowedOrigins=["https://app.xxxx.fun",//你的worker自定义域"https://e5fa97a5.my-pages-d7q.pages.dev"];functiongetCorsHeaders(request){constorigin=request.headers.get("Origin");constheaders={"Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type","Vary":"Origin"};if(origin&&allowedOrigins.includes(origin)){headers["Access-Control-Allow-Origin"]=origin;}returnheaders;}functionjsonResponse(request,data,status=200){returnResponse.json(data,{status,headers:getCorsHeaders(request)});}exportdefault{asyncfetch(request,env){consturl=newURL(request.url);constorigin=request.headers.get("Origin");// CORS 预检if(request.method==="OPTIONS"){if(origin&&!allowedOrigins.includes(origin)){returnnewResponse("CORS origin denied",{status:403});}returnnewResponse(null,{status:204,headers:getCorsHeaders(request)});}// 测试接口if(request.method==="GET"&&url.pathname==="/api/hello"){returnjsonResponse(request,{success:true,message:"Hello from Cloudflare Workers",time:newDate().toISOString()});}// 查询留言if(request.method==="GET"&&url.pathname==="/api/messages"){try{constresult=awaitenv.DB.prepare(`SELECT id, name, message, created_at FROM messages ORDER BY id DESC`).all();returnjsonResponse(request,{success:true,messages:result.results});}catch(error){returnjsonResponse(request,{success:false,message:"查询数据库失败",error:error.message},500);}}// 新增留言if(request.method==="POST"&&url.pathname==="/api/messages"){try{constdata=awaitrequest.json();constname=String(data.name||"").trim();constmessage=String(data.message||"").trim();if(!name||!message){returnjsonResponse(request,{success:false,message:"name 和 message 不能为空"},400);}if(name.length>50||message.length>1000){returnjsonResponse(request,{success:false,message:"内容长度超出限制"},400);}constresult=awaitenv.DB.prepare(`INSERT INTO messages (name, message) VALUES (?, ?)`).bind(name,message).run();returnjsonResponse(request,{success:true,id:result.meta.last_row_id},201);}catch(error){returnjsonResponse(request,{success:false,message:"写入数据库失败",error:error.message},500);}}// 原来的 echo 接口if(request.method==="POST"&&url.pathname==="/api/echo"){try{constdata=awaitrequest.json();returnjsonResponse(request,{success:true,received:data});}catch{returnjsonResponse(request,{success:false,message:"请求体必须是合法 JSON"},400);}}returnjsonResponse(request,{success:false,message:"Not Found"},404);}};

在 Cloudflare 部署设置中填写:

配置项内容
生产分支main
根目录/
构建命令留空
部署命令npx wrangler deploy

五、部署并测试 Worker

部署成功后,Cloudflare 会提供类似地址:

https://my-worker.你的账号.workers.dev

后续也可以绑定自定义域名:【计算】——【Workers 和 Pages】——【my-worker】——【域】

这里我们添加了一个自定义域名

1、测试GET接口

curl-ihttps://api.xxxx.fun/api/hello

2、测试POST接口

curl-i-XPOST https://api.xxxx.fun/api/echo\-H"Content-Type: application/json"\-d'{"name":"张三","message":"你好"}'

六、绑定D1数据库到Worker

进入【Workers 和 Pages】——【my-worker】——【绑定】——【添加绑定】——选择【D1 database】

配置项内容
变量名称DB,和wrangler.jsonc 中的binding:DB一致
D1 数据库选择my-database

七、测试D1 API

#测试查询接口curl-ihttps://api.xxxx.fun/api/messages#测试写入接口curl-i-XPOST https://api.xxxx.fun/api/messages\-H"Content-Type: application/json"\-d'{"name":"张三","message":"这条数据保存到D1了"}'

正常返回:200,成功查询和写入

八、创建 Pages 前端

在 GitHub 的my-pages仓库中创建:

index.html

<h2>留言板</h2><inputid="name"placeholder="你的名字"><br><br><textareaid="message"placeholder="留言内容"></textarea><br><br><buttononclick="submitMessage()">提交留言</button><buttononclick="loadMessages()">加载留言</button><preid="result">等待操作……</pre><script>constAPI_BASE="https://api.xxxx.fun";//你的pages自定义域asyncfunctionsubmitMessage(){constname=document.getElementById("name").value.trim();constmessage=document.getElementById("message").value.trim();if(!name||!message){alert("请填写姓名和留言");return;}constresponse=awaitfetch(`${API_BASE}/api/messages`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name,message})});constdata=awaitresponse.json();document.getElementById("result").textContent=JSON.stringify(data,null,2);if(response.ok){document.getElementById("name").value="";document.getElementById("message").value="";awaitloadMessages();}}asyncfunctionloadMessages(){constresponse=awaitfetch(`${API_BASE}/api/messages`);constdata=awaitresponse.json();document.getElementById("result").textContent=JSON.stringify(data,null,2);}loadMessages();</script>

九、部署Pages

进入 Cloudflare:【Workers 和 Pages】——【创建应用程序】——【Pages】——【连接 Github】——【选择my-pages】

配置填写:

配置项内容
生产分支main
构建命令留空
输出目录/
根目录/

部署成功后也同样绑定一个自定义域名:app.xxxx.fun。绑定后,前端地址为:https://app.xxxx.fun

十、最终测试

打开前端页面https://app.xxxx.fun

测试:

  1. 填写姓名;
  2. 填写留言;
  3. 点击“提交留言”;
  4. 页面请求 Workers;
  5. Workers 写入 D1;
  6. 页面重新查询并显示留言。

功能均正常

总结

本项目实现了从 GitHub 自动部署,到 Pages 前端、Workers API、D1 数据库存储的完整闭环,完成了一个可实际使用的 Cloudflare Serverless 留言板。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 5:00:39

基于MATLAB的植保无人机全覆盖路径规划与遗传算法优化

简介&#xff1a;本资源是一套面向农业自动化与智能控制领域的MATLAB实践项目&#xff0c;专为具备基础编程与优化算法知识的高校学生、科研人员及农业无人机开发者设计&#xff0c;聚焦多无人机协同农药喷洒路径规划这一典型工程问题。压缩包共含10个文件&#xff08;9个.m脚本…

作者头像 李华
网站建设 2026/8/30 5:00:05

PHP邮件发送管理系统源码:批量群发、SMTP配置与队列重试实战

简介&#xff1a;这是一套基于ThinkPHP框架开发的PHP邮件发送管理系统源码&#xff0c;面向Web开发者与运维人员&#xff0c;解决批量、可控、可监控的自动化邮件投递需求&#xff0c;适用于营销推广、通知提醒、用户注册验证等场景。资源包为ZIP格式&#xff0c;大小18.68MB&a…

作者头像 李华
网站建设 2026/8/30 4:59:46

谐波小波在ISAR目标识别中的应用:Matlab实现与特征提取全解析

简介&#xff1a;本资源是一套面向电子信息工程、计算机及数学专业本科生的ISAR成像教学实践工具&#xff0c;聚焦谐波小波在逆合成孔径雷达目标识别中的应用&#xff0c;解决课程设计、期末大作业与毕业设计中算法实现与图像质量提升的实际需求。压缩包共16个文件&#xff08;…

作者头像 李华
网站建设 2026/8/30 4:59:34

MATLAB实现IF97水物性程序:从公式翻译到独立编译部署

简介&#xff1a;本资源是一套基于IAPWS-IF97国际标准的水与水蒸气热物性计算MATLAB实现&#xff0c;面向能源、化工、制冷及热力系统设计领域的工程师与高校科研人员&#xff0c;解决高精度水物性参数&#xff08;如密度、焓、比热容、声速等&#xff09;在宽温压范围&#xf…

作者头像 李华
网站建设 2026/8/30 4:59:14

本地确定性风格检查:构建AI写作质量评估工具

很长时间以来&#xff0c;AI 写作辅助工具和内容生成模型已经深入开发者的日常工作。我们既享受大模型带来的效率提升&#xff0c;也面对一个现实问题&#xff1a;AI 生成的文字往往带着明显的“机器味”&#xff0c;包括句式重复、连接词滥用、逻辑跳跃以及高频套话。更麻烦的…

作者头像 李华
网站建设 2026/8/30 4:58:21

网易2018运维校招笔试题解析:从Linux到Kubernetes的考点与排障思维

“运维工程师”这四个字&#xff0c;在2018年校招季的网易笔试卷上&#xff0c;意味着什么&#xff1f;一晃几年过去&#xff0c;技术栈迭代了好几轮&#xff0c;但回过头来看这套题的设计思路&#xff0c;依然能品出不少关于运维岗位本质的东西。这两天整理硬盘&#xff0c;翻…

作者头像 李华