引入一种处理 HTTP 请求和服务资产的新方法

如果您正在安装 DFINITY Canister SDK 的任何 0.7.0(或更高版本)版本,您可能已经注意到这些版本引入了一些用于处理 HTTP 查询和前端资产的重大改进。 当这些更改正式发布到 DFINITY Canister SDK 的下一个公开发布版本中时,它们将改变您在互联网计算机上构建和部署应用程序的方式。

如果您正在创建新项目,则对底层架构的更改对您的开发工作流程几乎没有影响(如果有的话)。 事实上,您可能会发现新架构使构建在 Internet Computer 上运行的应用程序成为一种更熟悉的体验。

但是,如果您有任何现有项目,则需要计划一次性迁移到新架构。 不必立即完成向新架构的迁移,但更新您的项目以利用这些更改最终将使上传和管理前端资产变得更加容易。 == 替换引导代码:回顾

在我们描述新架构之前,了解一些关于我们正在替换的旧方法以及代码在这一点上的工作方式的背景信息是很有用的。 以前,在互联网计算机上开发前端涉及添加具有“retrieve()”函数的前端资产容器。 retrieve() 函数将采用路径并返回一个 blob。 retrieve() 函数返回的 blob 将有一个 index.js 文件,其中包含一些称为 bootstrap 代码的 JavaScript 和静态 HTML。 在互联网计算机上将应用程序部署为智能合约(称为canister)后,使用执行的`<CANISTER_ID>.ic0.app` URL 访问容器 bootstrap 代码依次执行以下步骤:

  • 创建了一个安全的工作人员来包含您的私钥。

  • Polyfill window.ic 为正在运行的应用程序提供一些机制,以便它可以与互联网计算机通信。

  • index.js 为路径调用容器的 retrieve() 方法,并对其求值。

  • 将文档对象模型 (DOM) 和页面的控制权传递给容器的 JavaScript 代码。

这种“引导”工作流程与人们通常构建 Web 应用程序的方式完全不同。 例如,这种方法不支持直接加载 HTML 或下载 PNG 文件等资产。 资产处理需要从另一个域(例如,AWS 存储桶)加载资产或在 JavaScript 中加载资产,将它们转换为数据 URI,然后相应地设置 src 属性。 以这种方式处理资产会导致浏览器出现问题,例如:

  • 不等待重新布局页面。

  • 延迟加载资产。

  • 带外执行 JavaScript。

bootstrap 方法在安全性和去中心化方面提供了优势,但这些优势被前端开发人员和应用程序用户没有预料到的糟糕的 HTTP 和资产处理所抵消。

去年,DFINITY Canister SDK 团队一直在收集和评估来自开发者社区的反馈。 基于该反馈,团队决定提供更灵活的开发人员体验,同时继续提供等效的安全模型。

使容器能够响应 HTTP 请求

在考虑了不同提案的优缺点后,团队决定采用一种允许容器直接响应 HTTP 请求的架构。 使用这种新方法,DFINITY Canister SDK 实现了一个 HTTP 中间件服务器。

HTTP 中间件服务器通过执行以下操作来处理 HTTP 请求:

  • 接收HTTP请求并将其方法、uri、headers和body转换成Candid结构。

  • 解析请求的容器标识符。

  • 实例化一个代理与容器对话。

  • 调用 http_request() 查询方法。

如果容器实现了 http_request() 方法,HTTP 中间件将解码响应,获取标头和正文,并构造 HTTP 响应。 如果容器没有实现 http_request() 方法,为了向后兼容,中间件会返回一个引导 polyfill,指出弃用作为警告。 对于过程中的任何错误,HTTP 中间件返回以下错误代码:

  • 400 Bad Request 用于任何无效请求(例如,如果 HTTP 中间件无法找到或解码容器 ID)。

  • 500 Internal Server Error 来自 HTTP 中间件本身的错误(例如,如果它无法连接到副本)

  • 502 Bad Gateway,如果错误来自副本本身(包括容器陷阱)。

如果发生任何这些错误,“dfx”命令行界面会在响应正文中提供更多详细信息。

重新审视资产存储容器

为了使这种过渡更容易,使用较新版本的“dfx”构建的新项目和现有项目将包括一个改进的资产容器,默认情况下支持“http_request()”方法。 这意味着您上传的资产(包括图像等二进制资产)将可以通过浏览器的 URL 直接访问。 例如,在一个新项目中,sample-asset.txt 文件将在发布到 https://<CANISTER_ID>.raw.ic0.app/sample-asset.txt 的互联网计算机后上传并可用。

将来,我们还将为管理资产容器缓存、处理默认资产和提供 HTTP 特定功能提供额外的支持。

路由

/api(用于副本)和 /_(用于工具目的)路由均由 HTTP 请求规范保留。 您可以在应用程序中根据需要使用所有其他路由,从而无需依赖单独的哈希路由器。

新 DFX 项目的结构

在讨论如何迁移现有项目之前,让我们先来看看一个新项目。 前端更改包括以下内容:

  • dfx.json 包含资产容器的 frontend 键,该键现在指向 index.html 文件,而不是 index.js JavaScript 入口点。

  • package.json 文件现在默认支持 Webpack 5。

  • webpack.config.js 文件现在以不同的方式为每个具有 frontend 键的容器生成容器导入列表。

  • src/<project_name>_assets/src/index.html 文件是一个新的模板文件,你可以用你自己的 index.html 文件替换你的前端。 当找不到文件时,默认情况下它由资产容器提供。

  • index.js 文件已被修改以支持agent和 actor的创建。

==agent和actor创建

在新的架构下,我们明确地创建一个agent实例,然后创建我们将用于容器的actor。 在`index.js`文件中,这意味着以前只有一个`import`来自`dfx`生成的文件,现在则有两个。

例如,项目中新的`index.js`文件提供了类似这样的代码。

import { Actor, HttpAgent } from '@dfinity/agent';
import { idlFactory as example_idl, canisterId as example_id } from 'dfx-generated/example';

const agent = new HttpAgent();
const example = Actor.createActor(example_idl, { agent, canisterId: example_id });

像这个例子说明的那样显式地创建代理和参与者更好,原因如下:

  • 首先,agent本身完全可以由应用程序配置,actor也是如此。 例如,只有在构建agent时才能设置身份验证,因此如果要管理用户身份,则需要在创建agent之前进行。

  • 其次,明确创建agent和actor可以让您更好地控制何时实例化这些对象。 如果你想要一个 React 钩子或一个 Angular 服务来创建actor,这种方法可以让你很容易地做到这一点。

迁移现有项目

如果您有一个现有项目,那么在您更新 DFINITY Canister SDK 后它可能无法无缝运行。 不幸的是,在这种情况下,直接迁移路径是不可能的。 迁移当前前端的最佳方法是创建一个新项目并将代码手动移动到新结构中。 === 认证和未认证的前端资产

随着 Internet Computer 主网 Beta 的推出,所有服务前端资产的项目都使用新的 HTTP 查询架构。 此外,Internet Computer 的发布引入了一项新功能,可以将前端资产作为已签名的认证数据提供服务,这些数据可以被视为经过身份验证和安全的数据,也可以作为未经认证的原始数据提供服务。 未通过认证过程的前端资产使用 raw.ic0.app URL 后缀提供。 经过认证的前端资产使用 .ic0.app URL 后缀。

当前的所有教程都说明了服务于未经认证的前端资产的应用程序。 学习如何构建一个使用经过认证的前端资产查询结果的应用程序是一个高级开发主题。 有关如何返回认证数据以响应查询的信息,请参阅接口规范与其他开发人员联系DFINITY开发者论坛