# 上传文件

> Source: https://strapi.nodejs.cn/cms/api/rest/upload

🌐 REST API: Upload files

`/api/upload` REST API 端点使你能够将文件上传到媒体库，获取分页文件列表，更新文件元数据，以及从你的 Strapi 应用中删除文件。

🌐 The `/api/upload` REST API endpoints enable you to upload files to the Media Library, retrieve paginated file lists, update file metadata, and delete files from your Strapi application.

[媒体库功能](/cms/features/media-library) 在 Strapi 的后端服务器中由 `upload` 包提供支持。要向 Strapi 上传文件，你可以直接从管理面板使用媒体库，也可以使用 [REST API](/cms/api/rest)，可用的端点如下：

🌐 The [Media Library feature](/cms/features/media-library) is powered in the back-end server of Strapi by the `upload` package. To upload files to Strapi, you can either use the Media Library directly from the admin panel, or use the [REST API](/cms/api/rest), with the following available endpoints :

| 方法 | 路径 | 描述 |
| :----- | :------------------------- | :--------------------------- |
| GET | `/api/upload/files` | 获取文件列表 |
| GET | `/api/upload/files/page` | 获取分页文件列表 |
| GET | `/api/upload/files/:id` | 获取特定文件 |
| POST | `/api/upload` | 上传文件 |
| POST | `/api/upload?id=x` | 更新文件信息 |
| DELETE | `/api/upload/files/:id` | 删除文件 |

:::note Notes

- [文件夹](/cms/features/media-library#organizing-assets-with-folders) 是仅限管理员面板的功能，不属于内容 API（REST 或 GraphQL）。通过 REST 上传的文件位于自动创建的“API 上传”文件夹中。
- GraphQL API 不支持上传媒体文件。要上传文件，请使用 REST API 或直接从管理面板的 [媒体库](/cms/features/media-library) 添加文件。一些用于更新或删除已上传媒体文件的 GraphQL 变更仍然可能（详情请参见 [GraphQL API 文档](/cms/api/graphql#mutations-on-media-files)）。

:::

## 获取文件列表 {#get-a-list-of-files}

🌐 Get a list of files

2 个端点从媒体库返回文件：`/api/upload/files` 将每个文件作为平铺数组返回，而 `/api/upload/files/page` 使用标准分页响应返回文件。对于任何非简单的媒体库，请使用 `/api/upload/files/page`。

### 获取所有文件 {#get-all-files}

🌐 Get all files

`GET /api/upload/files` 返回媒体库中所有文件的扁平数组：

```json
[
  {
    "id": 1,
    "documentId": "a1b2c3...",
    "name": "photo.jpg",
    "url": "/uploads/photo.jpg",
    "mime": "image/jpeg",
    "size": 12.34
    // ...other file fields
  }
  // ...
]
```

此端点会忽略分页参数，并始终返回所有文件。对于大型媒体库，响应可能会非常大，因此建议使用 `/api/upload/files/page`。

🌐 This endpoint ignores pagination parameters and always returns every file. For large media libraries the response can be very large, so prefer `/api/upload/files/page` instead.

### 获取分页文件列表 {#get-a-paginated-list-of-files}

🌐 Get a paginated list of files

`GET /api/upload/files/page` 使用标准的 [分页响应](/cms/api/rest/sort-pagination) 返回文件，封装在 `data` 数组和 `meta.pagination` 对象中。

它接受与其他 REST 集合端点相同的查询参数：

🌐 It accepts the same query parameters as other REST collection endpoints:

| 参数 | 描述 |
| --- | --- |
| `pagination[page]` | 页码（以1为起始）。默认 `1`。 |
| `pagination[pageSize]` | 每页文件数量。默认使用 `api.rest.defaultLimit` [配置](/cms/configurations/api) (`25`)，如果设置了 `api.rest.maxLimit` 则上限为其值。 |
| `pagination[start]` | 基于偏移的分页：要跳过的文件数量。 |
| `pagination[limit]` | 基于偏移的分页：返回的最大文件数量。 |
| `pagination[withCount]` | 是否运行计数查询并在响应中包含 `total` 和 `pageCount`。默认值为 `true`。 |
| `filters` | 对结果进行 [过滤](/cms/api/rest/filters)。 |
| `sort` | 对结果进行 [排序](/cms/api/rest/sort-pagination#sorting)。 |
| `fields` | [选择](/cms/api/rest/populate-select#field-selection) 要返回的字段。 |
| `populate` | [填充](/cms/api/rest/populate-select#population) 关联关系。 |

:::note

分页参数使用嵌套格式（`pagination[page]=2&pagination[pageSize]=10`），而不是扁平格式（`page=2&pageSize=10`）。按页分页（`page`/`pageSize`）和按偏移分页（`start`/`limit`）是互斥的：将它们结合使用会返回 `400` 错误。有关两种分页方法的详细信息，请参见 [排序与分页](/cms/api/rest/sort-pagination#pagination)。

🌐 Pagination parameters use the nested format (`pagination[page]=2&pagination[pageSize]=10`), not the flat format (`page=2&pageSize=10`). Pagination by page (`page`/`pageSize`) and pagination by offset (`start`/`limit`) are mutually exclusive: combining them returns a `400` error. For details on both pagination methods, see [Sort & Pagination](/cms/api/rest/sort-pagination#pagination).

:::

**示例请求：获取10个文件的第二页:**
`GET /api/upload/files/page?pagination[page]=2&pagination[pageSize]=10`

**示例响应:**
```json
{
  "data": [
    {
      "id": 1,
      "documentId": "a1b2c3...",
      "name": "photo.jpg",
      "url": "/uploads/photo.jpg",
      "mime": "image/jpeg",
      "size": 12.34
      // ...other file fields
    }
  ],
  "meta": {
    "pagination": {
      "page": 2,
      "pageSize": 10,
      "pageCount": 4,
      "total": 100
    }
  }
}
```

在使用偏移分页时，`meta.pagination` 对象返回 `start` 和 `limit`，而不是 `page` 和 `pageSize`：

🌐 When using pagination by offset, the `meta.pagination` object returns `start` and `limit` instead of `page` and `pageSize`:

**示例请求：获取5个图片文件，跳过前20个，不要总数:**
`GET /api/upload/files/page?pagination[start]=20&pagination[limit]=5&pagination[withCount]=false&filters[mime][$startsWith]=image/`

**示例响应:**
```json
{
  "data": [
    // ...
  ],
  "meta": {
    "pagination": {
      "start": 20,
      "limit": 5
    }
  }
}
```

当 `pagination[withCount]` 是 `false` 时，计数查询将被跳过，并且 `total` 和 `pageCount` 将从响应中省略。

🌐 When `pagination[withCount]` is `false`, the count query is skipped and `total` and `pageCount` are omitted from the response.

## 上传文件 {#upload-files}

🌐 Upload files

将一个或多个文件上传到你的应用。

🌐 Upload one or more files to your application.

`files` 是唯一接受的参数，用于描述要上传的文件。其值可以是 Buffer 或 Stream。

:::info Signed URLs with private S3 buckets

在使用 AWS S3 并将 `ACL` 参数设置为 `"private"` 时，上传端点返回的文件 URL 会自动生成签名。签名 URL 包含 `X-Amz-Signature` 查询参数和响应中的 `isUrlSigned: true` 标志，使其即使在私有桶 ACL 下也可访问。签名 URL 的过期时间基于你的 `signedUrlExpires` 配置（默认：15 分钟）。

🌐 When using AWS S3 with the `ACL` parameter set to `"private"`, file URLs returned by the upload endpoints are automatically signed. Signed URLs include `X-Amz-Signature` query parameters and an `isUrlSigned: true` flag in the response, making them accessible despite the private bucket ACL. Signed URLs expire based on your `signedUrlExpires` configuration (default: 15 minutes).

:::

:::tip

上传图片时，包含一个 `fileInfo` 对象以设置文件名、替代文本和标题。

🌐 When uploading an image, include a `fileInfo` object to set the file name, alt text, and caption.

:::

<Tabs>
<TabItem value="browser" label="Browser">

```html
<form>
  
  <input type="file" name="files" />
  <input
    type="hidden"
    name="fileInfo"
    value='{"name":"homepage-hero","alternativeText":"Person smiling while
      holding laptop","caption":"Hero image used on the homepage"}'
  />
  <input type="submit" value="Submit" />
</form>

<script type="text/javascript">
  const form = document.querySelector('form');

  form.addEventListener('submit', async (e) => {
    e.preventDefault();

    await fetch('/api/upload', {
      method: 'post',
      body: new FormData(e.target)
    });
  });
</script>
```

```js

const file = await blobFrom('./1.png', 'image/png');
const form = new FormData();

form.append('files', file, "1.png");
form.append(
  'fileInfo',
  JSON.stringify({
    name: 'Homepage hero',
    alternativeText: 'Person smiling while holding laptop',
    caption: 'Hero image used on the homepage',
  })
);

const response = await fetch('http://localhost:1337/api/upload', {
  method: 'post',
  body: form,
});

```

:::caution

你必须在请求正文中发送 FormData。

🌐 You have to send FormData in your request body.

:::

## 上传入口文件 {#upload-entry-files}

🌐 Upload entry files

上传一个或多个将链接到特定条目的文件。

🌐 Upload one or more files that will be linked to a specific entry.

接受以下参数：

🌐 The following parameters are accepted:

| 参数 | 描述 |
| --- | --- |
|`files` | 要上传的文件。值可以是 Buffer 或 Stream。 |
|`path` (可选) | 文件将上传到的文件夹（仅在 strapi-provider-upload-aws-s3 上支持）。 |
| `refId` | 将与文件关联的条目 ID。 |
| `ref` | 文件将关联的模型的唯一 ID（uid）（详见下文）。 |
| `source` (可选) | 模型所在插件的名称。 |
| `field` | 文件将精确关联到的条目字段。 |

例如，给定 `Restaurant` 模型属性：

🌐 For example, given the `Restaurant` model attributes:

```json title="/src/api/restaurant/content-types/restaurant/schema.json"
{
  // ...
  "attributes": {
    "name": {
      "type": "string"
    },
    "cover": {
      "type": "media",
      "multiple": false,
    }
  }
// ...
}
```

以下是相应前端的示例代码：

🌐 The following is an example of a corresponding front-end code:

```html
<form>
  
  <input type="file" name="files" />
  <input type="text" name="ref" value="api::restaurant.restaurant" />
  <input type="text" name="refId" value="5c126648c7415f0c0ef1bccd" />
  <input type="text" name="field" value="cover" />
  <input type="submit" value="Submit" />
</form>

<script type="text/javascript">
  const form = document.querySelector('form');

  form.addEventListener('submit', async (e) => {
    e.preventDefault();

    await fetch('/api/upload', {
      method: 'post',
      body: new FormData(e.target)
    });
  });
</script>
```

:::caution

你必须在请求正文中发送 FormData。

🌐 You have to send FormData in your request body.

:::

## 更新文件信息 {#update-fileinfo}

🌐 Update fileInfo

更新应用中的文件。

🌐 Update a file in your application.

`fileInfo` 是唯一被接受的参数，用于描述要更新的文件信息：

```js

const fileId = 50;
const newFileData = {
  alternativeText: 'My new alternative text for this image!',
};

const form = new FormData();

form.append('fileInfo', JSON.stringify(newFileData));

const response = await fetch(`http://localhost:1337/api/upload?id=${fileId}`, {
  method: 'post',
  body: form,
});

```

## 模型定义 {#models-definition}

🌐 Models definition

向[模型](/cms/backend-customization/models)（或另一个插件的模型）添加文件属性就像添加一个新的关联。

🌐 Adding a file attribute to a [model](/cms/backend-customization/models) (or the model of another plugin) is like adding a new association.

以下示例允许你上传并附加一个文件到 `avatar` 属性：

🌐 The following example lets you upload and attach one file to the `avatar` attribute:

```json title="/src/api/restaurant/content-types/restaurant/schema.json"

{
  // ...
  {
    "attributes": {
      "pseudo": {
        "type": "string",
        "required": true
      },
      "email": {
        "type": "email",
        "required": true,
        "unique": true
      },
      "avatar": {
        "type": "media",
        "multiple": false,
      }
    }
  }
  // ...
}

```

以下示例允许你上传并附加多张图片到 `restaurant` 内容类型：

🌐 The following example lets you upload and attach multiple pictures to the `restaurant` content-type:

```json title="/src/api/restaurant/content-types/restaurant/schema.json"
{
  // ...
  {
    "attributes": {
      "name": {
        "type": "string",
        "required": true
      },
      "covers": {
        "type": "media",
        "multiple": true,
      }
    }
  }
  // ...
}
```
