60 行代码即可编写您的第一个 Deno 服务器 入门 指定域名 获取服务器库 添加路由 最后一步:日志中间件 Fin

2025-06-10

60 行代码即可实现你的第一个 Deno 服务器

入门

指定我们的域

获取服务器库

添加我们的路线

最后一步:日志中间件

今天,我们将用 60 行代码编写我们的第一个 Deno 服务器。Deno 自称是一个简单、现代且安全的 JavaScript 和 TypeScript 运行时,它使用 V8 引擎,并基于 Rust 构建。我是 TypeScript 的忠实粉丝,所以听到一个将 TypeScript 视为“一等公民”的运行时,我非常兴奋!

了解更多

如果您喜欢这篇文章,请考虑查看我的免费邮件列表YouTube 教程,以了解更多与 JavaScript 和 Typescript 相关的内容!

入门

首先,我们必须安装运行时。有很多依赖于操作系统的方法可以做到这一点,所以我将推荐你参考 Deno 文档来安装它。

安装 Deno 后,您应该能够deno --version在命令行中输入并看到类似以下内容:

deno 1.0.0
v8 8.4.300
typescript 3.9.2
Enter fullscreen mode Exit fullscreen mode

Deno 还很年轻,而且发展很快,所以如果您有更新的版本,我不会感到惊讶!

指定我们的域

对于我们的第一个服务器,我们假设我们正在维护某种虚拟书架。因此,我们的领域与书籍有关。我们可以使用 TypeScript 指定类型Book,并创建一个包含初始项的数组books。让我们在新目录中创建此文件并将其命名为server.ts

服务器.ts

type Book = {
  id: number;
  title: string;
  author: string;
};

const books: Book[] = [
  {
    id: 1,
    title: "The Hobbit",
    author: "J. R. R. Tolkien",
  },
];
Enter fullscreen mode Exit fullscreen mode

获取服务器库

Oak 服务器库似乎是迄今为止 deno 最普遍的服务器库。让我们使用它吧!

如果您熟悉 Node,您可能会认为我们使用了安装命令,并将版本维护在某种类似 package.json 的文件中。并非如此!相反,我们在 import 语句中指定包 URL,并在导入过程中确定版本。Deno 会首先检查我们是否有该资源的缓存版本,如果没有,则会获取并缓存它。

需要注意的是,我们指定的是 Oak 4.0.0 版本。如果不指定版本,我们只会获取最新版本!考虑到过程中可能出现的重大变更,这似乎很危险。

我们将从 oak 导入ApplicationRouter。它们将分别创建我们的应用服务器并允许我们配置路由。

我们可以向我们的根 URL 添加一条get路由,以响应“Hello world!”我们告诉我们的应用程序监听端口 8000。

import { Application, Router } from "https://deno.land/x/oak@v4.0.0/mod.ts";

const app = new Application();
const router = new Router();

router
  .get("/", (context) => {
    context.response.body = "Hello world!";
  })

app.use(router.routes());

await app.listen({ port: 8000 });
Enter fullscreen mode Exit fullscreen mode

这是一个正常运行的服务器,所以我们应该测试一下!在文件所在的目录中,运行以下命令:

deno run --allow-net server.ts
Enter fullscreen mode Exit fullscreen mode

您的应用程序现在正在监听端口 8000,因此您应该能够http://localhost:8000在浏览器中导航到该端口并查看我们的 Hello World 示例!

添加我们的路线

现在我们可以添加一些路线了!我将在我们的图书资源上设置一些常见的 CRUD 路线:get book查看所有图书、get book:id查看特定图书以及post book创建图书。

import { Application, Router } from "https://deno.land/x/oak@v4.0.0/mod.ts";

type Book = {
  id: number;
  title: string;
  author: string;
};

const books: Book[] = [
  {
    id: 1,
    title: "The Hobbit",
    author: "J. R. R. Tolkien",
  },
];

const app = new Application();

const router = new Router();

router
  .get("/", (context) => {
    context.response.body = "Hello world!";
  })
  .get("/book", (context) => {
    context.response.body = books;
  })
  .get("/book/:id", (context) => {
    if (context.params && context.params.id) {
      const id = context.params.id;
      context.response.body = books.find((book) => book.id === parseInt(id));
    }
  })
  .post("/book", async (context) => {
    const body = await context.request.body();
    if (!body.value.title || !body.value.author) {
      context.response.status = 400;
      return;
    }
    const newBook: Book = {
      id: 2,
      title: body.value.title,
      author: body.value.author,
    };
    books.push(newBook);
    context.response.status = 201;
  });

app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });
Enter fullscreen mode Exit fullscreen mode

我认为这段代码中唯一可能比较新或难以解释的地方是app.use(router.allowedMethods());。这只是一个方便的中间件,当某个路由方法不被允许时,它会通知客户端!

最后一步:日志中间件

让我们添加最后一个功能:记录每个请求花费多长时间的日志中间件:

import { Application, Router } from "https://deno.land/x/oak@v4.0.0/mod.ts";

type Book = {
  id: number;
  title: string;
  author: string;
};

const books: Book[] = [
  {
    id: 1,
    title: "The Hobbit",
    author: "J. R. R. Tolkien",
  },
];

const app = new Application();

// Logger
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(`${ctx.request.method} ${ctx.request.url} - ${ms}ms`);
});

const router = new Router();

router
  .get("/", (context) => {
    context.response.body = "Hello world!";
  })
  .get("/book", (context) => {
    context.response.body = books;
  })
  .get("/book/:id", (context) => {
    if (context.params && context.params.id) {
      let id = context.params.id;
      context.response.body = books.find((book) => book.id === parseInt(id));
    }
  })
  .post("/book", async (context) => {
    const body = await context.request.body();
    if (!body.value.title || !body.value.author) {
      context.response.status = 400;
      return;
    }
    const newBook: Book = {
      id: 2,
      title: body.value.title,
      author: body.value.author,
    };
    books.push(newBook);
    context.response.status = 201;
  });

app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 8000 });
Enter fullscreen mode Exit fullscreen mode

现在,无论何时您访问我们的服务器,路由路径和发送响应所需的时间都会记录到控制台。

就这样!我们的第一个 Deno 服务器仅用 60 行代码就完成了。我是 Deno 的忠实粉丝,期待着随着它的发展不断学习更多。我确实有一些问题和顾虑(例如,由于缺少锁文件,我想知道 Deno 是否以及如何允许开发者控制间接依赖项),但目前我只是喜欢摆弄这个新玩具。

了解更多

如果您喜欢这篇文章,请考虑查看我的免费邮件列表YouTube 教程,以了解更多与 JavaScript 和 Typescript 相关的内容!

鏂囩珷鏉ユ簮锛�https://dev.to/nas5w/your-first-deno-server-in-60-lines-20kk
PREV
您的第一个使用 Typescript 的 Node Express 应用程序目标初始设置创建我们的 Express 应用程序超越“Hello World”探索 Express 类型应用程序代码结论
NEXT
在 React 中编写自己的 useFetch Hook 我们的 useFetch 函数签名 在 Hook 中维护状态 当我们的 URL 或选项更改时运行效果 使用 Async Await 调用 Fetch 使用 Hook 总结