REST API: 上传文件

页面摘要: /api/upload REST API 端点使你可以将文件上传到 Media Library(媒体库)、检索分页的文件列表、更新文件元数据,并从你的 Strapi 应用中删除文件。

Media Library 功能在 Strapi 的后端服务端中由 upload 包提供支持。要将文件上传到 Strapi,你可以直接在 admin panel(管理面板)中使用 Media Library,也可以使用 REST API,其可用端点如下:

方法(Method)路径(Path)描述(Description)
GET/api/upload/files获取文件列表
GET/api/upload/files/page获取分页的文件列表
GET/api/upload/files/:id获取特定文件
POST/api/upload上传文件
POST/api/upload?id=x更新 fileInfo(文件信息)
DELETE/api/upload/files/:id删除文件
说明(Notes)
  • Folders(文件夹) 是一个仅限 admin panel(管理面板)的功能,不属于 Content API(REST 或 GraphQL)。通过 REST 上传的文件会被放置在自动创建的 "API Uploads" 文件夹中。
  • GraphQL API 不支持上传媒体文件。要上传文件,请使用 REST API,或直接在 admin panel(管理面板)中的 Media Library 添加文件。某些用于更新或删除已上传媒体文件的 GraphQL mutation 仍然是可行的(详见 GraphQL API 文档)。

Get a list of files

2 个端点会从 Media Library 返回文件:/api/upload/files 以扁平数组的形式返回所有文件,而 /api/upload/files/page 则使用标准的分页响应来返回文件。对于任何具有一定规模的 Media Library,都建议使用 /api/upload/files/page。

Get all files

GET /api/upload/files 会返回 Media Library 中所有文件的扁平数组:

[
  {
    "id": 1,
    "documentId": "a1b2c3...",
    "name": "photo.jpg",
    "url": "/uploads/photo.jpg",
    "mime": "image/jpeg",
    "size": 12.34
    // ...其它文件字段
  }
  // ...
]

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

Get a paginated list of files

GET /api/upload/files/page 使用标准的分页响应返回文件,并包裹在 data 数组和 meta.pagination 对象中。

它接受与其它 REST collection(集合)端点相同的查询参数:

参数(Parameter)描述(Description)
pagination[page]页码(从 1 开始)。默认值为 1。
pagination[pageSize]每页文件数。默认为 api.rest.defaultLimit 配置(25),若设置了 api.rest.maxLimit 则以该值为上限。
pagination[start]基于偏移量的分页:要跳过的文件数。
pagination[limit]基于偏移量的分页:要返回的最大文件数。
pagination[withCount]是否运行 count 查询并在响应中包含 total 和 pageCount。默认为 true。
filters对结果进行过滤。
sort对结果进行排序。
fields选择要返回哪些字段。
populate联表加载关联。
NOTE

分页参数使用嵌套格式(pagination[page]=2&pagination[pageSize]=10),而非扁平格式(page=2&pageSize=10)。基于页码的分页(page/pageSize)与基于偏移量的分页(start/limit)是互斥的:将它们组合使用会返回 400 错误。关于这两种分页方式的详细说明,请参阅 Sort & Pagination(排序与分页)。

请求:Example request: Get the second page of 10 files

GET /api/upload/files/page?pagination[page]=2&pagination[pageSize]=10

响应

{
  "data": [
    {
      "id": 1,
      "documentId": "a1b2c3...",
      "name": "photo.jpg",
      "url": "/uploads/photo.jpg",
      "mime": "image/jpeg",
      "size": 12.34
      // ...其它文件字段
    }
  ],
  "meta": {
    "pagination": {
      "page": 2,
      "pageSize": 10,
      "pageCount": 4,
      "total": 100
    }
  }
}

当使用基于偏移量的分页时,meta.pagination 对象会返回 start 和 limit,而不是 page 和 pageSize:

请求:Example request: Get 5 image files, skipping the first 20, without a total count

GET /api/upload/files/page?pagination[start]=20&pagination[limit]=5&pagination[withCount]=false&filters[mime][$startsWith]=image/

响应

{
  "data": [
    // ...
  ],
  "meta": {
    "pagination": {
      "start": 20,
      "limit": 5
    }
  }
}

当 pagination[withCount] 为 false 时,count 查询会被跳过,total 和 pageCount 也会从响应中省略。

Upload files

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

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

使用私有 S3 存储桶时的签名 URL(Signed URLs)

当 AWS S3 的 ACL 参数设置为 "private" 时,上传端点返回的文件 URL 会自动进行签名。签名 URL 包含 X-Amz-Signature 查询参数,并在响应中带有 isUrlSigned: true 标志,即便在私有存储桶 ACL 下也能访问这些 URL。签名 URL 的过期时间取决于你的 signedUrlExpires 配置(默认:15 分钟)。

TIP

上传图片时,请包含一个 fileInfo 对象来设置文件名、替代文本(alt text)和说明文字(caption)。

Browser

<form>
  <!-- Can be multiple files -->
  <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>

Node.js

import { FormData } from 'formdata-node';
import fetch, { blobFrom } from 'node-fetch';

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,
});

WARNING

你必须在请求体中发送 FormData。

Upload entry files

上传将与某个特定条目相关联的一个或多个文件。

接受以下参数:

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

例如,给定 Restaurant 模型的属性:

{
  // ...
  "attributes": {
    "name": {
      "type": "string"
    },
    "cover": {
      "type": "media",
      "multiple": false,
    }
  }
// ...
}

以下是一个对应的前端代码示例:

<form>
  <!-- Can be multiple files if you setup "collection" instead of "model" -->
  <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>
WARNING

你必须在请求体中发送 FormData。

Update fileInfo

更新你的应用中的一个文件。

fileInfo 是唯一被接受的参数,用于描述要更新的 fileInfo(文件信息):

import { FormData } from 'formdata-node';
import fetch from 'node-fetch';

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

向模型(或另一个插件的模型)添加文件属性,类似于添加一个新的关联。

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


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

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

{
  // ...
  {
    "attributes": {
      "name": {
        "type": "string",
        "required": true
      },
      "covers": {
        "type": "media",
        "multiple": true,
      }
    }
  }
  // ...
}