管理面板 API:Fetch 客户端

页面摘要: 在 React 组件内使用 useFetchClient,在其他位置使用 getFetchClient,即可在调用 Strapi API 时自动附带用户的身份验证令牌。两者都暴露 get、post、put 和 del 方法,并在收到 401 响应时自动刷新令牌。

Strapi 为管理面板提供了一个内置的 HTTP 客户端,可自动管理身份验证。插件开发者应当使用它,而不是原始的 fetch 或 axios。

useFetchClient 和 getFetchClient 都从 @strapi/strapi/admin 导出,并暴露相同的 get、post、put 和 del 方法。请根据调用的发起位置进行选择:

入口点使用场景
useFetchClient在 React 组件内部(在组件卸载时自动取消请求)
getFetchClient服务、工具函数、事件处理函数,或任何非 React 代码
WARNING

在深入阅读本页概念之前,请确保你已经:

获取数据 {#fetching-data}

最常见的操作是使用 get 获取数据。导入客户端,解构出所需的方法,然后 await 其结果:

在 React 组件内部 {#inside-a-react-component}

useFetchClient 是一个 React hook,会自动提供一个与组件生命周期绑定的 AbortSignal,因此在组件卸载时请求会被取消:

JavaScript

import { useFetchClient } from '@strapi/strapi/admin';

const MyComponent = () => {
  const { get } = useFetchClient();

  const fetchData = async () => {
    const { data } = await get('/my-plugin/my-endpoint');
    // data contains the parsed JSON response
  };
};

TypeScript

import { useFetchClient } from '@strapi/strapi/admin';

const MyComponent = () => {
  const { get } = useFetchClient();

  const fetchData = async () => {
    const { data } = await get('/my-plugin/my-endpoint');
    // data contains the parsed JSON response
  };
};

在 React 组件外部 {#outside-a-react-component}

getFetchClient 可在任何 JavaScript 上下文中工作。典型的模式是将调用封装在导出的辅助函数内,供插件其余部分导入使用:

JavaScript

import { getFetchClient } from '@strapi/strapi/admin';

const { get, del } = getFetchClient();

export const fetchItems = async () => {
  const { data } = await get('/my-plugin/items');
  return data;
};

export const deleteItem = async (id) => {
  await del(`/my-plugin/items/${id}`);
};

TypeScript

import { getFetchClient } from '@strapi/strapi/admin';

const { get, del } = getFetchClient();

export const fetchItems = async () => {
  const { data } = await get('/my-plugin/items');
  return data;
};

export const deleteItem = async (id: string) => {
  await del(`/my-plugin/items/${id}`);
};
NOTE

del 方法之所以这样命名,是因为 delete 是 JavaScript 中的保留字。

使用 post 和 put 发送数据 {#sending-data}

post 和 put 方法接受负载(payload)作为第二个参数:

JavaScript

import { getFetchClient } from '@strapi/strapi/admin';

const { post, put } = getFetchClient();

// Create a new item
export const createItem = async (payload) => {
  const { data } = await post('/my-plugin/items', payload);
  return data;
};

// Update an existing item
export const updateItem = async (id, payload) => {
  const { data } = await put(`/my-plugin/items/${id}`, payload);
  return data;
};

TypeScript

import { getFetchClient } from '@strapi/strapi/admin';

const { post, put } = getFetchClient();

// Create a new item
export const createItem = async (payload: Record<string, unknown>) => {
  const { data } = await post('/my-plugin/items', payload);
  return data;
};

// Update an existing item
export const updateItem = async (id: string, payload: Record<string, unknown>) => {
  const { data } = await put(`/my-plugin/items/${id}`, payload);
  return data;
};
TIP

当发送 FormData(例如文件上传)时,fetch 客户端会自动移除 Content-Type 请求头,以便浏览器设置正确的 multipart 边界。

配置请求 {#options}

所有方法都接受一个 options 对象作为最后一个参数:

OptionTypeDescription
paramsobject查询字符串参数。自动序列化。
headersRecord<string, string>额外的请求头。会与默认值合并。
signalAbortSignal用于取消请求。useFetchClient 会自动提供一个。
validateStatus(status: number) => boolean \| null用于决定哪些 HTTP 状态码应抛出错误的自定义函数。
responseType'json' \| 'blob' \| 'text' \| 'arrayBuffer'控制响应解析方式(见 Response types)。仅在 get 上有效。

查询参数 {#params}

传入 params 即可自动序列化查询字符串:

const { data } = await get('/content-manager/collection-types/api::article.article', {
  params: {
    page: 1,
    pageSize: 10,
    sort: 'title:asc',
  },
});

响应类型 {#response-types}

默认情况下,响应会被解析为 JSON。get 方法接受 responseType 选项来处理非 JSON 响应,例如文件下载、CSV 导出或二进制数据:

responseType valueResponse parsed as
jsonJSON 对象(默认)
blobBlob
text纯文本字符串
arrayBufferArrayBuffer

非 JSON 响应会在返回对象中包含 status 和 headers:

JavaScript

import { useFetchClient } from '@strapi/strapi/admin';

const DownloadButton = () => {
  const { get } = useFetchClient();

  const downloadFile = async (url) => {
    const { data: blob, status, headers } = await get(url, { responseType: 'blob' });
    // Process the blob, for example to trigger a file download
  };
};

TypeScript

import { useFetchClient } from '@strapi/strapi/admin';

const DownloadButton = () => {
  const { get } = useFetchClient();

  const downloadFile = async (url: string) => {
    const { data: blob, status, headers } = await get(url, { responseType: 'blob' });
    // Process the blob, for example to trigger a file download
  };
};

错误处理 {#error-handling}

当请求失败时,fetch 客户端会抛出 FetchError。使用 isFetchError 工具函数可以安全地检查错误:

JavaScript

import { useFetchClient, isFetchError } from '@strapi/strapi/admin';

const MyComponent = () => {
  const { get } = useFetchClient();

  const fetchData = async () => {
    try {
      const { data } = await get('/my-plugin/my-endpoint');
      // handle success
    } catch (error) {
      if (isFetchError(error)) {
        // error.status contains the HTTP status code
        console.error('Request failed:', error.status, error.message);
      } else {
        throw error; // re-throw non-fetch errors
      }
    }
  };
};

TypeScript

import { useFetchClient, isFetchError } from '@strapi/strapi/admin';

const MyComponent = () => {
  const { get } = useFetchClient();

  const fetchData = async () => {
    try {
      const { data } = await get('/my-plugin/my-endpoint');
      // handle success
    } catch (error) {
      if (isFetchError(error)) {
        // error.status contains the HTTP status code
        console.error('Request failed:', error.status, error.message);
      } else {
        throw error; // re-throw non-fetch errors
      }
    }
  };
};
NOTE

当请求返回 401 状态码时,fetch 客户端会自动刷新身份验证令牌并重试请求,然后才会抛出错误。此自动重试不适用于身份验证端点本身。

👉 关于服务器端错误处理(控制器、服务、中间件),请参阅 Error handling。