> ## 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.

# 上传

> 使用 put() 上传文件：文件路径、Blob/File 或字节，超过 90 MiB 时自动使用分片上传，以及用于直接从浏览器上传的上传令牌。

## `put(file, options)`

`put()` 上传一个文件并返回新对象。

```typescript theme={"system"}
const { id, url } = await blob.put("./photo.png", {
    name: "photo",
    prefix: "avatars",
});
```

### 输入

| 输入                        | 环境            | 备注                                                          |
| ------------------------- | ------------- | ----------------------------------------------------------- |
| `string`（文件路径）            | **仅 Node.js** | 通过 `fs.openAsBlob` 打开并**从磁盘流式传输**，绝不会被整个读入内存。扩展名取自路径的文件名部分。 |
| `Blob` / `File`           | Node.js 和浏览器  | `File` 会提供其 `name`（及其扩展名）。                                  |
| `Uint8Array`（包括 `Buffer`） | Node.js 和浏览器  | 传入 `filename` 以设置扩展名。                                       |
| `ArrayBuffer`             | Node.js 和浏览器  | 传入 `filename` 以设置扩展名。                                       |

对象的扩展名依次取自 `filename`、路径的文件名部分或 `File` 的名称。字节和普通 `Blob` 没有名称，因此上传它们时请**传入 `filename`**（例如 `"data.json"`）。

<Note>
  在 Node.js 中，无法打开的路径会抛出普通的 `Error`（`Cannot open file: <path>`，原始错误位于 `cause` 中）。在浏览器中，传入路径会更早失败，抛出导入 `node:fs` 时的错误。请改用来自 `<input type="file">` 的 `File`。
</Note>

### 选项

| 选项                | 类型                           | 说明                                                                                                         |
| ----------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `name`            | `string`                     | **不含扩展名**的对象名称，需匹配 `^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$`，不能包含 `..`，不能以 `-ex<digits>` 结尾。除非上传令牌已固定名称，否则为必填。 |
| `prefix`          | `string`                     | 类似文件夹的路径：最多 8 个符合 `^[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$` 的段，总长 256 个字符。                                      |
| `private`         | `boolean`                    | 默认 `false`。私有对象始终带有安全哈希，且 `url: null`。                                                                     |
| `security_hash`   | `boolean`                    | 在名称后追加 `_<hash>`。                                                                                          |
| `expire`          | `string`                     | `"30"`（天）、`"30d"` 或 `"168h"`；7 到 1825 天（Enterprise 最低可至 1 小时）。过期时间会成为 ID 的一部分。                             |
| `overwrite`       | `boolean`                    | 为 `false` 时，如果名称已被占用，则以 `OBJECT_ALREADY_EXISTS` 失败。**仅限简单上传。**                                             |
| `disposition`     | `"inline"` \| `"attachment"` | 对象的 `Content-Disposition`。                                                                                 |
| `auto_download`   | `boolean`                    | 强制下载（`application/octet-stream`）。                                                                          |
| `cache_control`   | `string`                     | `immutable`、`max-age=60..31536000` 或 `no-cache`（Enterprise）。                                               |
| `metadata`        | `Record<string, string>`     | Pro 和 Enterprise。键需匹配 `^[a-z0-9-]{1,64}$`（不能是 `sq-*`），最多 5 个键、512 字节。                                      |
| `checksum_sha256` | `string`                     | 64 个小写十六进制字符。不匹配时以 `CHECKSUM_MISMATCH` 失败，且不会存储任何内容。**仅限简单上传。**                                            |
| `filename`        | `string`                     | 文件名，其扩展名会成为对象的扩展名。默认为 `File` 的名称或路径的文件名部分。                                                                 |
| `mime_type`       | `string`                     | 仅在 `filename` 没有扩展名时用于选择扩展名。`Content-Type` 由服务器推断。                                                         |

完整的服务器端规则请参见 [Object Post](/zh/blob-reference/endpoint/post)。

### 结果

| 字段                                     | 类型               | 说明                                                                       |
| -------------------------------------- | ---------------- | ------------------------------------------------------------------------ |
| `id`                                   | `string`         | 不透明的对象 ID。[按原样存储](/zh/sdks/blob/client#对象-id)。                           |
| `private`                              | `boolean`        | 对象是否为私有。                                                                 |
| `url`                                  | `string \| null` | 公开 URL，私有对象则为 `null`（请使用 [`downloadUrl()`](/zh/sdks/blob/objects#下载链接)）。 |
| `expires_at`                           | `string`         | 对象的过期时间（如果设置了过期）。                                                        |
| `size`                                 | `number`         | 大小（字节）。                                                                  |
| `name`, `prefix`, `sha256`, `replaced` |                  | 仅限简单上传。                                                                  |
| `parts`                                | `number`         | 仅限分片上传：已发送的分片数量。                                                         |

## 简单上传和分片上传

`put()` 根据文件大小选择上传流程：

| 文件大小                            | 流程        | Endpoint                                                 |
| ------------------------------- | --------- | -------------------------------------------------------- |
| 不超过 **90 MiB**（94,371,840 字节，含） | 简单上传，一个请求 | [Object Post](/zh/blob-reference/endpoint/post)          |
| 超过 90 MiB，最多 **10 GiB**         | 分片（分块）上传  | [Chunked Init](/zh/blob-reference/endpoint/chunked-init) |

每个文件必须**至少 512 字节**；更小的文件会以 `FILE_TOO_SMALL` 失败。规则或上传令牌的 `max_size`，或者你的存储配额，可能会降低 10 GiB 的上限。

### 分片上传的执行过程

1. SDK 启动上传，服务器返回其分片限制（`max_size`、`max_parts`）。
2. 文件被拆分为大小为 `min(max_size, max(16 MiB, ceil(size / max_parts)))` 字节的分片。一个分片通常为 16 MiB 或更大，但当服务器的 `max_size` 更小时，分片也会更小。
3. 分片**每次并发发送 6 个**，这是服务器对进行中分片的限制。失败的分片会在 `maxRetries` 范围内[重试](/zh/sdks/blob/errors#重试策略)。
4. 所有分片到达后，SDK 完成上传。

如果某个分片最终失败，或完成上传失败，SDK 会**等待仍在进行中的分片**，然后**中止**上传，确保中止之后不会再有分片到达。原始错误会被抛出。**不支持续传**：请重新调用 `put()`。

<Warning>
  分片上传**不会检查 `overwrite: false` 或 `checksum_sha256`**。它始终会替换同名的现有对象。
</Warning>

<Note>
  一个账户最多可以有 **32 个未完成的分片上传**（与 S3 网关共享）；再多一个会以 `TOO_MANY_OPEN_UPLOADS` 失败。由于每个账户的分片每次并发发送 6 个，请**一次只运行一个大文件上传**。
</Note>

## 从浏览器上传

切勿将 API 密钥发送到浏览器。应由你的服务器生成一个短期有效的**上传令牌**，浏览器再使用该令牌上传。

<Tabs>
  <Tab title="服务器">
    ```typescript theme={"system"}
    import { SquareCloudBlob } from "@squarecloud/blob";

    const blob = new SquareCloudBlob(process.env.SQUARECLOUD_API_KEY);

    // e.g. inside your API route
    const { token } = await blob.uploadTokens.create({
        prefix: "avatars/",
        security_hash: true,
        max_size: 5 * 1024 * 1024,
        allowed_extensions: ["png", "jpg"],
    });
    // send only `token` to the browser
    ```
  </Tab>

  <Tab title="浏览器">
    ```typescript theme={"system"}
    import { SquareCloudBlob } from "@squarecloud/blob";

    const upload = new SquareCloudBlob(token);
    const { url } = await upload.put(input.files[0], { name: "avatar" });
    ```
  </Tab>
</Tabs>

使用令牌创建的客户端**只能调用 `put()`**，包括分片上传。其他任何方法都会以 `403 UPLOAD_TOKEN_NOT_ALLOWED` 失败。

### `uploadTokens.create(options)`

令牌会固定其生成时使用的每一个选项。

| 选项                   | 类型                       | 说明                                                    |
| -------------------- | ------------------------ | ----------------------------------------------------- |
| `name`               | `string`                 | 固定对象名称。不设置时，始终会应用安全哈希。                                |
| `prefix`             | `string`                 | 固定前缀。                                                 |
| `private`            | `boolean`                | 固定可见性。                                                |
| `security_hash`      | `boolean`                | 在名称后追加 `_<hash>`。                                     |
| `expire`             | `string`                 | 对象过期时间，与 `put()` 中相同。                                 |
| `max_size`           | `number`                 | 最大文件大小（字节）。                                           |
| `allowed_extensions` | `string[]`               | 1 到 20 个扩展名。                                          |
| `metadata`           | `Record<string, string>` | 应用于所上传对象的元数据。                                         |
| `expires_in`         | `number`                 | 令牌有效期（秒），60 到 3600（默认 900）。                           |
| `max_uses`           | `number`                 | 允许的上传次数，1 到 100（默认 1）。用完后令牌会以 `UPLOAD_TOKEN_USED` 失败。 |

它返回 `{ token, expires_at, max_uses }`。服务器端规则请参见 [Upload Tokens](/zh/blob-reference/endpoint/upload-tokens)。

<Note>
  `uploadTokens.create()` 是一个写操作，只有**一次尝试**：它永远不会被重试。
</Note>
