如今
在某些编程语言或运行时环境中,Websocket是一个真正的挑战。人们经常利用社区创建的解决方案或使用服务来应对这一挑战,但是对于Deno来说,这非常简单。
介绍
在本文中,我们将创建一个带有两个端点的REST API,其中一个将负责发出事件,在这种情况下,该事件将与包含消息数据的文档相对应。另一个将建立将从服务器发送消息到客户端的Websocket连接的连接。
为您提供更多上下文,在本文中,我们将使用以下技术:
在开始本文之前,我建议您安装了Deno,并且使用节点有简短的经验。
设置项目
要开始,请导航到您选择的目录并运行以下命令:
deno init .
上面的命令有望在工作区中创建一组文件,因此,我们初始化了一个DENO项目,并将对deno.jsonc
文件进行一些更改。
首先定义我们将使用任务Runner deno task
:
运行的一些命令
{
"tasks": {
"dev": "deno run --watch main.ts"
}
}
接下来,让我们定义一些需要导入项目中的依赖项:
{
// ...
"imports": {
"oak": "https://deno.land/x/oak@v12.5.0/mod.ts",
"evt": "https://deno.land/x/evt@v2.4.22/mod.ts"
}
}
随着deno.jsonc
的最后一次更改,我们可以将项目的配置视为最终确定,现在该使我们的手变得脏了!
Websocket示例
EventEmitter的设置
下一步将是实例化将在API中使用的事件发射器,当我们使用依赖关系evt时,我们可以创建一个完全type typesafe客户端,而我们唯一需要的是定义类型并将其传递为通用在.create()
方法中,这样:
// @/common/emitter.ts
import { Evt } from "evt";
export interface Todo {
title: string;
isDone: boolean;
createdBy: string;
}
export const todoEmitter = Evt.create<Todo>();
路由器定义
考虑到上几点,我们现在可以定义本文简介中提到的每条路线。
首先,我们需要导入我们刚刚创建的事件发射器。然后,我们将使用HTTP动词POST
创建路由,此路由旨在获取消息数据(在这种情况下为todo)。不忘记提及我们需要访问CreatedBy
标头,因此以后我们将拥有必要的数据来发出事件。
// @/router.ts
import { Router } from "oak";
import { todoEmitter } from "./common/emitter.ts";
export const router = new Router();
router.post("/todos", async (ctx) => {
const createdBy = ctx.request.headers.get("CreatedBy");
if (!createdBy) ctx.throw(400);
const { value } = ctx.request.body({ type: "json" });
const data = await value;
try {
await todoEmitter.postAndWait({ ...data, createdBy });
ctx.response.status = 200;
ctx.response.body = { isSuccessful: true };
} catch {
ctx.throw(400);
}
});
// ...
现在,我们已经在创建新的todo时发出了一个事件,我们现在可以创建GET
路线。首先,我们必须检查连接是否可以升级,如果不是,我们返回错误。接下来,我们将访问CreatedBy
标头以过滤发送给客户的消息。
实际上,todoEmitter
也是异步迭代器,如果TODO的创建者与CreatedBy
Header的创建者完全相同,我们可以直接迭代实例,然后发送Websocket。
// @/router.ts
import { Router } from "oak";
import { todoEmitter } from "./common/emitter.ts";
export const router = new Router();
// ...
router.get("/todos-ws", async (ctx) => {
if (!ctx.isUpgradable) ctx.throw(501);
const createdBy = ctx.request.headers.get("CreatedBy");
if (!createdBy) ctx.throw(400);
const ws = ctx.upgrade();
for await (const todo of todoEmitter) {
if (todo.createdBy === createdBy) {
ws.send(JSON.stringify(todo));
}
}
});
现在我们可以说我们已经注册了每条路线,这使我们可以进入下一个和最后一步。
服务器定义
在此步骤中,我们将导入上一个点中创建的路由,并对API进行基本配置。这样:
// @/main.ts
import { Application } from "oak";
import { router } from "./router.ts";
const app = new Application({ logErrors: false });
app.use(router.routes());
app.use(router.allowedMethods());
app.listen({ port: 8000 });
要启动该过程,只需运行以下命令:
deno task dev
结论
我希望您能发现这篇文章有帮助,无论您是在现有项目中使用信息还是只是尝试一下。
如果您在文章中注意到任何错误,请告诉我。而且,如果您想查看本文的源代码,则可以在下面链接的github存储库上找到它。