> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# 迁移到 v4

> @squarecloud/blob 4.0.0 的变化：更安全的重试策略、更少的默认重试次数、可选的 SavedRule.active_from，以及行为一致的单 ID 批量删除。

4.0.0 版本更改了 **SDK 的重试方式**，使其只重复可以安全重复的操作。**没有任何方法、选项或导出被重命名或移除。**

## 要求

保持不变：**Node.js 20** 或更新版本，或浏览器；ESM 和 CommonJS。

## 破坏性变更摘要

| v3.x                                              | v4.x                                                 |
| ------------------------------------------------- | ---------------------------------------------------- |
| 重试 `429`                                          | **永不重试**（分片上传的分片遇到 `TOO_MANY_CONCURRENT_CHUNKS` 时除外） |
| 写操作在网络错误和 `5xx` 时重试                               | 写操作只有**一次尝试**                                        |
| 仅在 `500` 和 `503` 时重试                              | 在**任何 `5xx`** 时重试（读操作和分片上传的分片）                       |
| `maxRetries` 默认为 `5`                              | 默认为 **`2`**                                          |
| 退避上限为 30 秒                                        | 上限为 **8 秒**：`min(8 s, 500 ms · 2^n) · U(0.5, 1)`     |
| `SavedRule.active_from: string`                   | `active_from?: string`（**可选**）                       |
| 只有一个 ID 的 `delete([id])` 会抛出 `PREFIX_NOT_ALLOWED` | 在 `failed` 中报告                                       |
| `BlobErrorCode` 中的 `RATE_LIMIT`                   | **已弃用**（仍保留在类型中）                                     |

## 不再重试 `429`

`RATE_LIMITED` 既涵盖按路由计算的时间窗口，也涵盖可能持续约 30 分钟的账户或 IP 封锁，因此 SDK 不再重试它。这包括简单上传的限制和 `TOO_MANY_CONCURRENT_UPLOADS`。请自行处理，并在再次尝试之前等待：

```typescript theme={"system"}
import { SquareCloudBlobError } from "@squarecloud/blob";

try {
    await blob.put(file, { name: "report" });
} catch (error) {
    if (error instanceof SquareCloudBlobError && error.code === "RATE_LIMITED") {
        // back off: queue the job for later instead of retrying right away
    }
    throw error;
}
```

唯一的例外是分片上传的分片遇到 `TOO_MANY_CONCURRENT_CHUNKS`：服务器在读取该分片之前就拒绝了它，因此 SDK 会在 `maxRetries` 范围内再次发送。

## 写操作只有一次尝试

网络错误和 `5xx` 现在只在 `GET` 调用和分片上传的分片上重试。以下调用只有**一次尝试**：

* 简单 `put()`，以及分片上传的启动、完成和中止；
* `update()`、`copy()`、`move()`、`delete()`；
* `rules.set()`、`uploadTokens.create()`、`shares.create()`、`shares.revoke()`。

仅当重复执行对你而言是安全的时候才自行重试写操作，例如对同一名称使用 `overwrite: true` 的 `put()`。参见[自行重试写操作](/zh/sdks/blob/errors#自行重试写操作)。

## 更少的重试，更短的退避

`maxRetries` 现在默认为 `2`（以前为 `5`），退避上限为 8 秒（以前为 30 秒）。如需在读操作和分片上传的分片上保留旧的重试预算：

```typescript theme={"system"}
const blob = new SquareCloudBlob(process.env.SQUARECLOUD_API_KEY, { maxRetries: 5 });
```

这不会恢复对 `429` 或写操作的重试。

## `SavedRule.active_from` 变为可选

API 只会为带有 `delete_after_days` 的规则发送 `active_from`。在 TypeScript 中，请处理 `undefined`：

```typescript theme={"system"}
const rules = await blob.rules.get();

for (const rule of rules) {
    if (rule.active_from) {
        console.log(`${rule.prefix} starts deleting at ${rule.active_from}`);
    }
}
```

## 只有一个 ID 的 `delete([id])`

只有一个 ID 的批量操作现在与其他批量操作一样，会在 `failed` 中报告 `PREFIX_NOT_ALLOWED`，而不是抛出异常：

```typescript theme={"system"}
// v3: threw SquareCloudBlobError (PREFIX_NOT_ALLOWED)
// v4:
const { failed } = await blob.delete([id]);
// failed: [{ id, code: "PREFIX_NOT_ALLOWED" }]
```

使用普通字符串的 `delete(id)` 仍会抛出异常。

## `RATE_LIMIT` 已弃用

服务不再发送 `RATE_LIMIT`：账户或 IP 封锁为 `RATE_LIMITED`。旧代码仍保留在 `BlobErrorCode` 中，以便现有的比较仍能编译；请将它们改为 `RATE_LIMITED`。新增了 `DUPLICATE_RULE_PREFIX`。

## 修复

* 在读取中途被截断的响应体现在属于**网络错误**：它会在 `GET` 调用和分片上传的分片上重试，其他情况下则抛出原始的 `fetch` 错误（以前是 `UNKNOWN_ERROR`）。
* 失败的分片上传现在会在中止之前**等待仍在进行中的分片**，因此中止之后不会再有分片到达，也不会有请求比 `put()` 存活得更久。

## 检查清单

<Steps>
  <Step title="自行处理 429">
    捕获 `RATE_LIMITED` 并进行退避；SDK 不再重试它。
  </Step>

  <Step title="检查写操作">
    只为可以安全重复的写操作添加你自己的重试。
  </Step>

  <Step title="选择重试预算">
    如果你依赖读操作和分片上传分片上的旧尝试次数，请传入 `{ maxRetries: 5 }`。
  </Step>

  <Step title="更新类型">
    处理 `active_from` 为 `undefined` 的情况，并将 `RATE_LIMIT` 替换为 `RATE_LIMITED`。
  </Step>
</Steps>
