# 客户端和服务器之间的数据流概述

在 WooCommerce 购物车和结账模块中，服务器是关键事务性数据的权威来源。这包括：

-   购物车商品详情（商品、数量和价格）
-   购物车总额（例如，税费、费用、小计）
-   客户信息（收货地址和账单地址，以及其他客户数据）
    -   使用 [Additional Checkout Fields API](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields) 添加的附加字段也保存在服务器端。
-   配送方式和运费
-   其他购物车详情，例如已应用的优惠券

此类数据必须保存在服务器端，以确保不同用户会话和设备上的准确性、一致性和可靠性。
瞬态的 UI 状态——例如，临时验证状态，或 UI 相关的交互，如展开/折叠的部分，应保留在客户端，并且除非需要跨页面加载维护特定状态，或者该状态对用户的结账过程至关重要，否则不应自动保存在服务器上。

您可能希望将数据从服务器传输到客户端，反之亦然。本文档将概述购物车/结账模块中的一般概念和数据流，并提供链接或指导，以帮助您了解一些常见用例。

## 数据存储在哪里？

所有与购物车、客户和订单相关的数据都存储在服务器上，要么存储在数据库中，要么存储在客户的会话中。当数据发送到客户端时，它存储在 [`@wordpress/data`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/) 数据存储中。

## 如何将服务器端 (PHP) 数据导入到客户端 (JavaScript) 以及反之

由于服务器是权威来源，因此客户端的所有数据最终都应该传输到服务器，如果需要将其与订单一起持久化。

此外，还存在一种情况，即您的客户端需要只能在服务器端派生的数据，例如在 WooCommerce 设置仪表盘中设置的配置选项，或者来自外部服务的数据（例如，快递费率或支付 API）。

### 服务器 (PHP) 到 客户端 (JavaScript)

有两种方法可以将数据从服务器传输到客户端，具体取决于数据是静态的还是动态的。

#### 静态数据

静态数据不太可能因为用户的操作而发生变化，例如来自 WooCommerce 设置仪表盘的某个选项。 将这些数据传递给客户端的推荐方法是使用 `AssetDataRegistry`。

当数据添加到此处时，它会被序列化并发送到客户端，并在页面加载时生效。 它不会因为用户的操作而改变，例如将商品添加到购物车或更改地址。

可以将键/值对添加到注册表中，如下所示：

```php
add_action(
    'woocommerce_blocks_loaded',
    function() {
      $asset_data_registry = \Automattic\WooCommerce\Blocks\Package::container()->get( \Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry::class );
      $asset_data_registry->add( 'namespace/value', 'this is a custom value' );
    }
);
```

如果存在重复的键，则不会被覆盖。 使用唯一的标识符非常重要，建议使用 `namespace/value` 以确保键的唯一性。

要在客户端获取这些数据，请使用 `wc.wcSettings.getSetting`，如下所示：

```js
const myCustomValue = wc.wcSettings.getSetting(
	'namespace/value',
	'Fallback value.'
);
```

#### 动态数据

动态数据是指可能响应用户操作而发生变化的数据，例如更改位置或购物车中的商品。 在这种情况下，您需要将这些数据添加到购物车 API 响应中。 购物车响应在用户购物过程中的许多路由中都会发送，并且几乎每个由购物车/结账模块触发的 API 响应都包含它。

要添加数据，您需要扩展 API 响应。 请参阅 [在 Store API 中暴露您的数据](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-data.md)。

### 客户端 (JavaScript) 到 服务器 (PHP)

从客户端获取数据到服务器可以通过三种不同的方式实现：

#### 结账字段更新

当用户更新结账字段时，数据会立即发送到服务器。 对于附加字段，这些数据通过 PUT 请求发送到 `/checkout` 接口。 对于地址字段，这些数据通过 POST 请求发送到 `cart/update-customer` 接口（通过批量）。 这两种方式都会返回一个更新后的购物车，然后将其应用到客户端，并更新总价。

#### 附加到 Store API 请求

这对于不需要服务器立即响应的情况非常有用，例如，如果您在结账流程中添加了一个新块，并且该块包含一个需要与订单一起保存的表单字段。如果该表单字段只需要保存，而不需要更新购物车中的任何其他值，则应将数据与结账请求一起发送。 [将包含自定义字段的自定义内部块添加到 WooCommerce 结账块](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-custom-fields.md) 文档提供了一个使用 `setExtensionData` 以及扩展 Store API 以在现有请求中接收您的数据的工作示例。

#### 使用 `extensionCartUpdate` 按需发送数据

您可能希望立即将数据发送到服务器，而不是等待 Store API 请求。如果数据可能更新购物车，例如添加费用、更改可用的配送方式或更改税率，则可能需要这样做。

[使用 Store API 按需更新购物车](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-update-cart.md) 文档概述了如何执行此操作。

## 数据在购物车/结账块中何时发送/接收？

### 页面加载

在页面加载时，如果存在购物车或结账块，则购物车状态将与初始请求一起发送，并加载到客户端的 [`@wordpress/data`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/) 数据存储中。

在页面加载时，`wc/store/cart` 和 `wc/store/checkout` 数据存储会从服务器加载数据。`wc/store/payment` 数据存储部分数据来自服务器，但需要一些客户端处理才能完成，才能注册所有付款方式。

### 在结账表单中输入客户数据

当购物者在表单中输入数据时，数据会立即写入 `wc/store/cart` 数据存储，并且会调用一个防抖方法 `[pushChanges](https://github.com/woocommerce/woocommerce/blob/4861ec250ef1789f814f4209755165e8abe7b838/plugins/woocommerce-blocks/assets/js/data/cart/push-changes.ts#L167)。 该方法将客户数据发送到服务器，服务器将这些数据与客户信息关联并持久化。 完整的购物车数据作为响应返回，并且数据存储会使用这些数据进行更新。

需要注意的是，如果服务器上运行的代码修改了客户的地址信息，这些修改会反映在响应中。

例如，如果某个插件修改地址数据以确保所有城市名称都大写，并且购物者在城市字段中输入 "london"，那么当数据返回给客户端时，文本会变为 "London"，并且输入字段会更新。

在购物者与表单交互时修改表单字段会造成不好的用户体验，因此，建议不要在用户与表单交互时进行这些修改，而是在服务器上处理结账操作时进行修改。

### 添加优惠券

当购物者展开优惠券表单时，状态会存储在本地。 这种类型的数据不会发送到服务器。 当购物者按下“应用”按钮时，会发送添加优惠券的请求。 会发送一个 Store API 请求，并返回一个新的购物车，然后将该购物车应用。

### 更改配送方式

当购物者更改配送方式时，会发送一个 Store API 请求，并返回一个新的购物车，然后将该购物车应用。

### 更改支付方式

当购物者更改支付方式时，不会自动发送 Store API 请求到服务器。 如果需要在支付方式更改时更新服务器，并且在订单提交之前，正确的做法是使用 `[cartExtensionUpdate](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-update-cart.md)`。

### 添加/编辑订单备注

添加或编辑订单备注时，这些备注会存储在客户端本地，只有当购物者提交结账表单时，才会将这些备注发送到服务器。

## 购物车

上面“结账”部分中列出的项目也适用于“购物车”模块（除了更改支付方式之外，购物者在“购物车”模块中无法选择支付方式，除非是快速支付方式，其行为方式不同，并且完全在客户端实现）。

### 更改商品数量、添加或移除商品

当购物者更新商品的数量、从购物车中移除商品，或添加商品（例如，从“购物车交叉销售”模块中添加商品）时，会发送一个 Store API 请求。 客户端本地的购物车会使用响应进行更新。

### 使用配送计算器

它的行为方式与“结账”模块中的地址表单相同，但是，配送计算器中的地址只有在邮编有效，并且所有必填字段都已填写时，才会发送到服务器。