平时使用多了赛博菩萨的服务,忍不住想研究下Cloudflare Workers的开发,踩了不少坑,也有了一些心得,就新开一篇博客记录下流水账吧,不定时更新,为了方便,以下Cloudflare都简称为CF。

本地开发部署

CF Workers本地开发使用的工具名叫wrangler,可以方便的搭建本地测试环境,用来进行调试,缺点是如果需要使用CF的服务(例如KV,D1)等,就不能在本地进行了,需要部署到Workers上进行调试了,但是即便这样,相比CF网页版的源码编辑器,wrangler也是大大方便了我们的开发。

Wrangler的安装

wrangler的使用,需要安装node.js,官网下载地址https://nodejs.org/en

安装完之后,可以修改下npm源,加快下载速度,以下是华为云的镜像源:

1
npm config set registry https://mirrors.huaweicloud.com/repository/npm/

wrangler的安装有两种方式,一种是全局安装:

1
npm install -g wrangler

一种是安装在当前工作目录:

1
npm install wrangler --save-dev

根据情况择一使用就行,最大的区别是前一种安装不管在哪里都可以直接使用wrangler命令,后一种则需要进入安装了wrangler的工作目录中使用npx wrangler来运行命令,以下都以全局安装为例进行说明。

Wrangler的使用

wrangler常用的几个命令:

进行登录 wrangler login

新建项目 wrangler generate <项目名称>

调试模式 wrangler dev

进行部署 wrangler deploy

在项目工作目录下,调试和部署可以分别使用 npm startnpm run deploy 进行

程序入口

1
2
3
4
5
export default {
async fetch(request, env, ctx) {
return new Response('Hello World!');
},
};

触发器入口

1
2
3
4
5
export default {
async scheduled(controller, env, ctx) {
console.log(`Hello World!`);
},
};

使用触发器,需要在工作目录下的wrangler.toml文件中添加计划的选项字段:

1
2
[triggers]
crons = [ "1 * * * *" ]

KV的使用

新建KV命名空间 wrangler kv namespace create <名称>

显示KV命名空间 wrangler kv namespace list

删除KV命名空间 wrangler kv namespace delete --namespace-id <KV的ID>

建立KV命名空间后,需要打开工作目录下的wrangler.toml文件,添加以下字段:

1
2
3
[[kv_namespaces]]
binding = "绑定的KV名称"
id = "KV ID"

然后再部署一遍,就能将KV和Workers项目绑定了

需要注意的是,本地访问的时候不能读取到KV的值

在程序中的使用,读取对应键的值:

1
tmp = await env.绑定的KV名称.get("键名");

改写对应键的值:

1
tmp = await env.绑定的KV名称.put("键名");

D1数据库的使用

建立方式和KV类似,不再赘述了,同样建好后需要打开工作目录下的wrangler.toml文件,添加以下字段:

1
2
3
[[d1_databases]]
binding = "绑定的D1名称"
database_id = "数据库ID"

使用的话,数据库都通过SQL语言进行操作,使用案例如下:

1
2
3
4
await env.绑定的D1名称.prepare(`
INSERT INTO test (username, id, qid)
VALUES (?, ?, ?)
`).bind(test.username, test.id, test.qid).run();
1
2
3
4
5
await env.绑定的D1名称.prepare(`
UPDATE test
SET qid = ?
WHERE username = ? AND id = ?
`).bind(test.qid, test.username, test.id).run();

需要注意的就是bind()中的变量顺序和SQL语句中的一一对应

prepare()用来预处理SQL语句,run()用来执行SQL语句,如果分开写,两个调用都需要加await

除了run(),也能使用all()来执行,两者效果一样,可以互为别名

run()all()返回值是JSON格式的,操作结果会在返回对象的.results里边,查询类操作返回数据,操作类的返回空,简单的使用案例如下:

1
2
3
4
5
6
7
const logSearch = env.绑定的D1名称.prepare(`
SELECT time, message
FROM logs
ORDER BY time ASC
`);
data = await logSearch.all();
return data.results.map(row => `${row.time} ==> ${row.message}`).join('\n')

踩的那些坑

async函数返回值是Promise对象,获取返回值一定要使用await进行处理,不然会一直处于pending状态

待更新…