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

# Blob 对象复制

> 通过 POST /v1/objects/copy 在 Blob Storage 内部复制、移动或重命名文件，在服务器端完成，无需下载。

<ParamField header="Authorization" type="string" placeholder="API Key" required>
  你账户的 API 密钥。你可以在[账户设置](https://squarecloud.app/zh/account/security)中找到它。
</ParamField>

对象复制会以新的名称、前缀或可见性复制一个文件，完全在服务器上完成：没有任何字节经过你的应用。设置 `move: true` 时，源文件会在之后被删除，这就是**重命名**或**移动**文件的方式。需要 `blob:write` scope 和付费计划。

* 副本会保留源文件的扩展名、内容类型、缓存、disposition 和元数据。
* 复制会计入你的存储配额；移动则不会。
* 目标始终使用当前的存储，因此移动也是将 2026 年 9 月更新之前存储的旧版文件转换为新格式的方式（参见[对象更新](/zh/blob-reference/endpoint/update#旧版文件)）。

<ParamField body="source" type="string" required>
  要复制的文件的 id。
</ParamField>

<ParamField body="destination" type="object" required>
  副本的目标位置。

  <Expandable title="属性">
    <ParamField body="name" type="string" required>
      新名称，不含扩展名。模式与[对象上传](/zh/blob-reference/endpoint/post)相同。
    </ParamField>

    <ParamField body="prefix" type="string">
      新前缀。省略则将副本存储在根目录。
    </ParamField>

    <ParamField body="private" type="boolean">
      副本的可见性。默认与源文件相同。
    </ParamField>

    <ParamField body="expire" type="string | null">
      从现在起计算的新过期时间（`30d`、`6h`）。`null` 会移除过期时间。省略则保留源文件的过期日期。
    </ParamField>

    <ParamField body="security_hash" type="boolean" default="false">
      在新名称后添加随机后缀。私有副本始终带有该后缀。
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="move" type="boolean" default="false">
  `true` 会在复制成功后删除源文件。
</ParamField>

<ParamField body="overwrite" type="boolean" default="false">
  `true` 会替换目标位置已存在的文件。否则请求返回 `409 OBJECT_ALREADY_EXISTS`。
</ParamField>

### 速率限制

<Note>每 10 秒 10 次请求（`RATE_LIMITED`，429）。</Note>

### 响应

<ResponseField name="status" type="string">
  成功为 "success"，否则为 "error"。
</ResponseField>

<ResponseField name="response" type="object">
  <Expandable title="展开对象">
    <ResponseField name="id" type="string">
      新文件的 id。
    </ResponseField>

    <ResponseField name="private" type="boolean">
      新文件是否为私有。
    </ResponseField>

    <ResponseField name="url" type="string | null">
      新文件的公开 URL，私有时为 `null`。
    </ResponseField>

    <ResponseField name="expires_at" type="ISO 8601">
      新文件将被删除的时间。仅当文件会过期时出现。
    </ResponseField>

    <ResponseField name="size" type="number">
      文件大小，单位为字节。
    </ResponseField>

    <ResponseField name="source" type="string">
      源文件的 id。
    </ResponseField>

    <ResponseField name="moved" type="boolean">
      源文件是否已被删除。
    </ResponseField>

    <ResponseField name="replaced" type="boolean">
      是否替换了目标位置已存在的文件。
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash 重命名 theme={null}
  curl --request POST \
    --url 'https://blob.squarecloud.app/v1/objects/copy' \
    --header 'Authorization: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
      "source": "pub/3155597145698959364/uploads/IMG_2041.png",
      "destination": { "name": "cover", "prefix": "posts/launch" },
      "move": true
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://blob.squarecloud.app/v1/objects/copy', {
    method: 'POST',
    headers: {
      Authorization: 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      source: 'pub/3155597145698959364/uploads/IMG_2041.png',
      destination: { name: 'cover', prefix: 'posts/launch' },
      move: true,
    }),
  });
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "status": "success",
    "response": {
      "id": "pub/3155597145698959364/posts/launch/cover.png",
      "private": false,
      "url": "https://blob.squarecloud.dev/pub/3155597145698959364/posts/launch/cover.png",
      "size": 416230,
      "source": "pub/3155597145698959364/uploads/IMG_2041.png",
      "moved": true,
      "replaced": false
    }
  }
  ```
</ResponseExample>

### 错误

| 代码                                                           | HTTP | 触发情况                               |
| ------------------------------------------------------------ | ---- | ---------------------------------- |
| `INVALID_OBJECT`                                             | 400  | `source` 缺失、格式错误或不属于你。             |
| `INVALID_OBJECT_NAME` / `INVALID_OBJECT_PREFIX`              | 400  | 目标名称或前缀不符合模式。                      |
| `INVALID_DESTINATION`                                        | 400  | `private` 或 `security_hash` 不是布尔值。 |
| `INVALID_OBJECT_EXPIRE`                                      | 400  | `expire` 不是 1 小时到 1825 天之间的时长。     |
| `INVALID_OBJECT_SECURITY_HASH`                               | 400  | 在私有副本上设置了 `security_hash: false`。  |
| `SAME_OBJECT`                                                | 400  | 目标就是源文件。                           |
| `PERMISSION_DENIED`                                          | 401  | 账户没有有效的付费计划。                       |
| `UPGRADE_REQUIRED`                                           | 403  | 该过期时间需要更高级别的计划。                    |
| `STORAGE_QUOTA_EXCEEDED`                                     | 403  | 本次复制将超出内置存储配额。                     |
| `OBJECT_NOT_FOUND`                                           | 404  | 源文件不存在。                            |
| `OBJECT_ALREADY_EXISTS`                                      | 409  | 目标位置已存在文件，且 `overwrite` 不为 `true`。 |
| `RATE_LIMITED`                                               | 429  | 10 秒内超过 10 次请求。                    |
| `COPY_FAILED`                                                | 500  | 复制失败。请重试。                          |
| `PRIVATE_STORAGE_UNAVAILABLE` / `PUBLIC_STORAGE_UNAVAILABLE` | 503  | 存储暂时不可用。请重试。                       |
