首页 > web前端 > js教程 > 正文

服务器操作已修复

Linda Hamilton
发布: 2024-10-21 06:22:02
原创
669 人浏览过

服务器操作的出现是为了减少客户端代码简化需要与服务器通信的交互。这是一个优秀的解决方案,可以让开发人员编写更少的代码。然而,在其他框架中实施它存在一些不容忽视的挑战。

在本文中,我们将讨论这些问题以及如何在 Brisa 中找到解决方案。

为什么需要服务器操作?

要了解服务器操作提供的内容,回顾一下过去与服务器的通信方式很有用。您可能习惯于每次与服务器交互时执行以下操作:

  1. 捕获浏览器事件(客户端)
  2. 标准化和序列化数据(客户端)
  3. 向服务器发出请求(客户端)
  4. 在端点 API 中处理请求 (服务器)
  5. 回复必要的数据(服务器)
  6. 等待服务器响应并处理(客户端)
  7. 更新客户端上的数据并呈现更改(客户端)

这七个动作每次交互都会重复。例如,如果您的页面有 10 个不同的交互,您将重复非常相似的代码 10 次,仅更改请求类型、URL、发送的数据和客户状态等详细信息。

一个熟悉的例子是
一个:

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

在服务器中:

app.post("/api/search", async (req, res) => {
  const { query } = req.body;
  const data = await search(query);
  res.json(data);
});
登录后复制
登录后复制
登录后复制

增加客户端包大小......以及开发人员的挫败感。

Server Actions have been fixed


沮丧的开发者

服务器操作如何工作

服务器操作这些操作封装在远程过程调用(RPC)中,它管理客户端-服务器通信,减少客户端上的代码并将逻辑集中在服务器上:

  1. 捕获浏览器事件(RPC 客户端)
  2. 标准化和序列化数据(RPC 客户端)
  3. 向 RPC 服务器发出请求 (RPC 客户端)
  4. 使用数据在服务器上执行操作(RPC 服务器)
  5. 选项 1:
  • 从服务器渲染并将流发送到客户端(RPC 服务器)
  • 处理流的块,以便更改可见(RPC 客户端)
  1. 选项 2:
  • 回复必要的数据并将属性从服务器存储传输到客户端存储(RPC 服务器)
  • 使正在监听更改的信号对存储中的更改做出反应(RPC 客户端)

这里的一切都是由 Brisa RPC 为您完成的。

Server Actions have been fixed


远程过程调用

这将是来自服务器组件的代码:

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
在这里,开发人员不编写客户端代码,因为它是服务器组件。 onInput 事件在反跳后接收,由客户端 RPC 处理,而服务器 RPC 使用“操作信号”来触发已向该存储属性注册信号的 Web 组件。

如您所见,这显着减少了服务器代码,最重要的是,客户端上的代码大小不会随着每次交互而增加。 RPC 客户端代码占用固定的 2 KB,无论您有 10 个还是 1000 个这样的交互。这意味着客户端包大小

增加 0 字节,换句话说,不会增加。

Server Actions have been fixed


客户端包大小为 0 字节

此外,在需要重新渲染的情况下,这是在服务器上完成的,并以 HTML 流的形式返回,使用户比传统方式更早地看到更改,在传统方式中,您必须在客户端上完成此工作服务器响应。

这样:

  • 改善用户体验(用户体验
  • 改善开发体验(DX)

Server Actions have been fixed


快乐的开发者

Brisa Server Actions 与其他框架之间的差异

1. 要捕获的事件数量

在 React 等其他框架中,他们只关注

操作作为 form onSubmit 的一部分,而不是任何事件。

这是一个问题,因为有许多非表单事件也应该从服务器组件处理,而无需添加客户端代码。例如,输入的 onInput 用于执行 自动建议onScroll 用于加载 无限滚动onMouseOver 进行悬停

Server Actions have been fixed


应用程序比预期更具互动性

2. 对服务器操作有更多的 HTML 控制

许多框架也将 HTMX 库视为服务器操作的一个非常不同的替代方案,事实上,它带来了非常好的想法,可以与服务器操作结合起来,只需在 HTML 中添加额外的属性即可发挥更大的潜力。 RPC Client可以考虑,比如我们之前见过的debounceInput。还有其他 HTMX 想法,例如在发出请求时显示旋转器的指示器,或者能够处理 RPC 客户端中的错误。

Server Actions have been fixed


HTMX 想法

3. 关注点分离

当服务器操作在 React 中引入时,出现了新的范式转变,许多开发人员在使用它们时必须更改心理芯片。

我们希望使其尽可能熟悉Web平台,这样,您就可以从服务器捕获序列化事件并使用其属性。唯一有点不同的事件是已经传输了 FormData 并具有 e.formData 属性的 onSubmit,不过,其余的事件属性都是可交互的。这是一个示例重置表单

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

在此示例中,根本没有客户端代码,在服务器操作期间,您可以使用 CSS 使用指示器禁用提交按钮,以便表单无法提交两次,并且在在服务器上执行操作后的同一时间,使用 e.formData 访问表单数据,然后使用事件的相同 API 重置表单

在精神上,这与使用网络平台非常相似。唯一的区别是所有服务器组件的所有事件都是服务器操作。

这样,就实现了真正的关注点分离,没有必要“用户服务器”“使用客户端”放入您的组件不再

请记住一切都只在服务器上运行。唯一的例外是在客户端上运行的src/web-components文件夹,并且事件正常

Server Actions have been fixed


两个不同的世界,但一致

4. 事件传播

在 Brisa 中,服务器操作在服务器组件之间传播,就好像它们是 DOM 事件一样。也就是说,从一个Server Action中,你可以调用一个Server Component的prop的事件,然后执行父Server Component的Server Action,等等

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

在这种情况下,onAfterMyAction 事件在父组件上执行,并且可以在服务器上执行操作。这对于在服务器上执行影响多个服务器组件的操作非常有用。

Server Actions have been fixed


传播动作

4. 两个世界之间的沟通

特别是在过去的几周里,在 X(以前的 Twitter)上进行了多次讨论之后,Web 组件变得有点不受欢迎。然而,作为HTML的一部分,它是与服务器操作交互最佳方式,原因如下:

  1. 您可以从服务器捕获任何Web 组件事件并生成客户端-服务器通信。示例 。这非常强大,因为 Web 组件内的所有事件都只是客户端逻辑,而没有放置任何服务器逻辑,只需在使用 Web 组件时从服务器进行服务器操作即可。
  2. HTTP 协议 可用于其设计目的,流媒体中传输超文本 (HTML),这样如果在重新从服务器操作渲染 Web 组件的任何属性都会更新,RPC 客户端的差异算法使 Web 组件无需太多努力即可更新。 Brisa 中的 Web 组件 属性 是信号,它们使 Web 组件的内部部分做出反应而无需重新渲染。这个过程在其他框架中变得非常复杂,使得 RPC 服务器必须通过网络处理 JSON 或 JS,而不是 HTML,这使得流式传输的实现更加复杂。

在 Web Components 中使用属性需要序列化,就像不使用 Web Components 将数据从服务器传输到客户端一样,因此,使用两者,无需管理额外的序列化

注意:如果您有兴趣,我会在另一篇文章中解释流式 HTML 并使用比较算法对其进行处理。

Server Actions have been fixed


通过网络传输的超文本

5.新概念:行动信号

在 Brisa 中,我们添加了一个新概念,为服务器操作提供更多功能,这个概念称为 “操作信号”。 “行动信号”的想法是,您有2 个商店,一个位于服务器,一个位于客户端

为什么是2家店?

默认服务器存储 仅在请求级别存在。并且您可以共享客户端不可见的数据。例如,您可以让中间件设置用户并有权访问任何服务器组件中的敏感用户数据。通过生活在请求级别,不同请求之间不可能发生冲突,因为每个请求都有其自己的存储并且不存储在任何数据库中,当请求完成,默认消亡。

另一方面,在客户端商店中,它是一个商店,每个属性在消费时都是一个信号,也就是说,如果它已更新,正在侦听该信号的 Web 组件会做出反应。

但是,“操作信号”的新概念是我们可以将服务器存储的生命周期延长到请求之外。为此,需要使用以下代码:

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

此transferToClient方法,将服务器数据共享到客户端存储并转换为信号。通过这种方式,很多时候不需要从服务器进行任何重新渲染,您可以简单地通过服务器操作对正在侦听该信号的 Web 组件的信号做出反应。

这次商店转移使服务器商店的生命现在:

渲染初始服务器组件→客户端→服务器操作→客户端→服务器操作...

因此它从仅在请求级别生存到永久生存,兼容页面之间的导航。

Server Actions have been fixed


在两个世界(服务器/客户端)之间共享数据

示例:

app.post("/api/search", async (req, res) => {
  const { query } = req.body;
  const data = await search(query);
  res.json(data);
});
登录后复制
登录后复制
登录后复制

在此示例中,我们延长了错误存储属性的寿命,不是在客户端上使用,而是在服务器操作中重用,然后最终在服务器操作的重新渲染中重用。在这种情况下,作为非敏感数据,没有必要对其进行加密。此示例代码全部发生在服务器上,甚至重新渲染,用户将在服务器上渲染后看到错误,其中服务器 RPC 将在流中发送 HTML 块,客户端 RPC 将对其进行处理以进行比较并显示向用户反馈错误。

6. 仅加密敏感数据

如果在服务器操作中使用了渲染级别存在的某个变量,则在安全级别,许多框架(如 Next.js 14)所做的就是加密此数据以创建在以下位置使用的数据的快照渲染的时间。这或多或少没问题,但是始终加密数据会产生相关的计算成本并且它并不总是敏感数据。

在 Brisa 中,为了解决这个问题,有不同的请求,在初始渲染中它有一个值,并且在服务器操作中您可以捕获它在此请求中具有的值。

<input
  debounceInput={300}
  onInput={async (e) => {
    // All this code only runs on the server
    const data = await search(e.target.value);
    store.set("query", data);
    store.transferToClient(["query"]);
  }}
/>
登录后复制
登录后复制

这在某些情况下很有用,但并不总是有用,例如,如果您执行 Math.random,初始渲染和服务器操作执行之间肯定会有所不同。

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

这就是为什么我们创建了“行动信号”概念,以将数据服务器存储传输到客户端存储,并且开发者可以随意决定是否加密或不

有时,您可能希望传输初始渲染中已存在的数据,而不是从服务器操作查询数据库,即使它需要关联的加密。为此,您只需使用:

app.post("/api/search", async (req, res) => {
  const { query } = req.body;
  const data = await search(query);
  res.json(data);
});
登录后复制
登录后复制
登录后复制

当你这样做时:

<input
  debounceInput={300}
  onInput={async (e) => {
    // All this code only runs on the server
    const data = await search(e.target.value);
    store.set("query", data);
    store.transferToClient(["query"]);
  }}
/>
登录后复制
登录后复制

Web 组件(客户端)内部始终会加密,但在服务器上始终会解密。

注意:Brisa 使用 aes-256-cbc 进行加密,这是 OpenSSL 推荐的用于安全加密信息的加密算法组合。加密密钥是在项目构建过程中生成的。

Server Actions have been fixed


在两个世界(服务器/客户端)之间共享加密数据

结论

在 Brisa 中,虽然我们喜欢支持轻松编写 Web 组件,但目标是能够在没有客户端代码的情况下制作 SPA,并且仅在纯客户端交互或必须触及 Web API 时才使用 Web 组件。这就是为什么服务器操作如此重要,因为它们允许与服务器交互而无需编写客户端代码。

我们鼓励您尝试 Brisa,您只需在终端中运行此命令:bun create brisa,或者尝试一些示例来看看它是如何工作的。

参考

  • 服务器操作约定
  • 服务器操作行为
  • 带有服务器操作的表单
  • 嵌套操作
  • 服务器端验证和错误处理
  • 反跳服务器操作
  • 乐观更新
  • 实际重新渲染
  • 使用服务器操作导航到另一个页面
  • 访问 Cookie
  • 服务器操作的安全性
  • 行动信号
  • 传输敏感数据
  • 服务器操作中的道具
  • 在反向代理中使用服务器操作

以上是服务器操作已修复的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!