API: fetchBaseQuery reference">API: fetchBaseQuery reference">
跳至主要内容

fetchBaseQuery

这是一个围绕 fetch 的非常小的包装器,旨在简化 HTTP 请求。它不是 axiossuperagent 或任何其他更重量级库的完整替代品,但它将涵盖您绝大多数 HTTP 请求需求。

fetchBaseQuery 是一个工厂函数,它生成一个与 RTK Query 的 baseQuery 配置选项兼容的数据获取方法。它接受来自 fetch 的 RequestInit 接口的所有标准选项,以及 baseUrlprepareHeaders 函数、可选的 fetch 函数、paramsSerializer 函数和 timeout

基本用法

要使用它,在您 创建 API 服务定义 时导入它,将其作为 fetchBaseQuery(options) 调用,并将结果作为 createApi 中的 baseQuery 字段传递。

src/services/pokemon.ts
// Or from '@reduxjs/toolkit/query/react'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const pokemonApi = createApi({
// Set the baseUrl for every endpoint below
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (builder) => ({
getPokemonByName: builder.query({
// Will make a request like https://pokeapi.co/api/v2/pokemon/bulbasaur
query: (name: string) => `pokemon/${name}`,
}),
updatePokemon: builder.mutation({
query: ({ name, patch }) => ({
url: `pokemon/${name}`,
// When performing a mutation, you typically use a method of
// PATCH/PUT/POST/DELETE for REST endpoints
method: 'PATCH',
// fetchBaseQuery automatically adds `content-type: application/json` to
// the Headers and calls `JSON.stringify(patch)`
body: patch,
}),
}),
}),
})

签名

fetchBaseQuery 签名
type FetchBaseQuery = (
args: FetchBaseQueryArgs,
) => (
args: string | FetchArgs,
api: BaseQueryApi,
extraOptions: ExtraOptions,
) => FetchBaseQueryResult

type FetchBaseQueryArgs = {
baseUrl?: string
prepareHeaders?: (
headers: Headers,
api: Pick<
BaseQueryApi,
'getState' | 'extra' | 'endpoint' | 'type' | 'forced'
>,
) => MaybePromise<Headers | void>
fetchFn?: (
input: RequestInfo,
init?: RequestInit | undefined,
) => Promise<Response>
paramsSerializer?: (params: Record<string, any>) => string
isJsonContentType?: (headers: Headers) => boolean
jsonContentType?: string
timeout?: number
} & RequestInit

type FetchBaseQueryResult = Promise<
| {
data: any
error?: undefined
meta?: { request: Request; response: Response }
}
| {
error: {
status: number
data: any
}
data?: undefined
meta?: { request: Request; response: Response }
}
>

参数

baseUrl

(必需)

通常是一个字符串,例如 https://api.your-really-great-app.com/v1/。如果您不提供 baseUrl,它将默认为请求发出位置的相对路径。您应该始终指定它

prepareHeaders

(可选)

允许您在每个请求上注入标头。您可以在端点级别指定标头,但通常您需要在此处设置通用标头,例如 authorization。作为一种便捷机制,第二个参数允许您使用 getState 访问您的 redux 存储,以防您存储需要的信息(例如身份验证令牌)。此外,它还提供对 extraendpointtypeforced 的访问,以解锁更细粒度的条件行为。

您可以直接修改 headers 参数,并且返回它也是可选的。

prepareHeaders 签名
type prepareHeaders = (
headers: Headers,
api: {
getState: () => unknown
extra: unknown
endpoint: string
type: 'query' | 'mutation'
forced: boolean | undefined
},
) => Headers | void

paramsSerializer

(可选)

一个函数,可用于对传递到 params 的数据应用自定义转换。如果您不提供此函数,params 将直接传递给 new URLSearchParams()。对于某些 API 集成,您可能需要利用它来使用类似于 query-string 库的东西来支持不同的数组类型。

fetchFn

(可选)

一个覆盖窗口上默认 fetch 函数的 fetch 函数。在 SSR 环境中可能很有用,您可能需要利用 isomorphic-fetchcross-fetch

timeout

(可选)

一个以毫秒为单位的数字,表示请求在超时之前可以花费的最长时间。

isJsonContentType

(可选)

一个回调函数,它接收一个 Headers 对象,并确定 FetchArgs 参数的 body 字段是否应该通过 JSON.stringify() 进行字符串化。

默认实现检查 content-type 标头,并将匹配 "application/json""application/vnd.api+json" 之类的值。

jsonContentType

(可选)

当为具有可 JSON 化主体但没有显式 content-type 标头的请求自动设置 content-type 标头时使用。默认值为 "application/json"

常见用法模式

在请求上设置默认标头

prepareHeaders 最常见的用例是自动为您的 API 请求包含 authorization 标头。

"设置
import { fetchBaseQuery } from '@reduxjs/toolkit/query'
import type { RootState } from './store'

const baseQuery = fetchBaseQuery({
baseUrl: '/',
prepareHeaders: (headers, { getState }) => {
const token = (getState() as RootState).auth.token

// If we have a token set in state, let's assume that we should be passing it.
if (token) {
headers.set('authorization', `Bearer ${token}`)
}

return headers
},
})

单个查询选项

您可以在每个请求的基础上定义更多行为。query 字段可以返回一个包含 RequestInit 接口中可用的任何默认 fetch 选项以及以下附加选项的对象

端点请求选项
interface FetchArgs extends RequestInit {
url: string
params?: Record<string, any>
body?: any
responseHandler?:
| 'json'
| 'text'
| `content-type`
| ((response: Response) => Promise<any>)
validateStatus?: (response: Response, body: any) => boolean
timeout?: number
}

const defaultValidateStatus = (response: Response) =>
response.status >= 200 && response.status <= 299

设置主体

默认情况下,fetchBaseQuery 假设您发出的每个请求都将是 json,因此在这些情况下,您只需设置 url 并在适当的时候传递 body 对象即可。对于其他实现,您可以手动设置 Headers 来指定内容类型。

json

 // omitted
endpoints: (builder) => ({
updateUser: builder.query({
query: (user: Record<string, string>) => ({
url: `users`,
method: 'PUT',
body: user // Body is automatically converted to json with the correct headers
}),
}),

text

 // omitted
endpoints: (builder) => ({
updateUser: builder.query({
query: (user: Record<string, string>) => ({
url: `users`,
method: 'PUT',
headers: {
'content-type': 'text/plain',
},
body: user
}),
}),

设置查询字符串

fetchBaseQuery 提供了一种简单的机制,通过将对象传递给 new URLSearchParms() 来将 object 转换为序列化查询字符串。如果这不能满足您的需求,您有两个选择

  1. paramsSerializer 选项传递给 fetchBaseQuery 以应用自定义转换
  2. 构建您自己的查询字符串并在 url 中设置它
 // omitted
endpoints: (builder) => ({
updateUser: builder.query({
query: (user: Record<string, string>) => ({
url: `users`,
// Assuming no `paramsSerializer` is specified, the user object is automatically converted
// and produces a url like /api/users?first_name=test&last_name=example
params: user
}),
}),

解析响应

默认情况下,fetchBaseQuery 假设您获得的每个 Response 都将被解析为 json。如果您不希望发生这种情况,您可以通过指定替代响应处理程序(如 text)来自定义行为,或者完全控制并使用接受原始 Response 对象的自定义函数 - 允许您使用任何 Response 方法

responseHandler 字段可以是

type ResponseHandler =
| 'content-type'
| 'json'
| 'text'
| ((response: Response) => Promise<any>)

"json""text" 值指示 fetchBaseQuery 使用相应的 fetch 响应方法来读取主体。content-type 将检查标头字段以首先确定这是否看起来是 JSON,然后使用这两个方法之一。回调允许您自己处理主体。

将响应解析为文本
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const customApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: `users`,
// This is the same as passing 'text'
responseHandler: (response) => response.text(),
}),
}),
}),
})
关于返回未定义主体的响应的说明

如果您向仅返回具有未定义主体的 `200` 的 API 发出 `json` 请求,`fetchBaseQuery` 将将其作为 `undefined` 传递,并且不会尝试将其解析为 `json`。这在某些 API 中很常见,尤其是在 `delete` 请求中。

处理非标准响应状态码

默认情况下,`fetchBaseQuery` 会 `拒绝` 任何状态码不是 `2xx` 的 `Response` 并将其设置为 `error`。这与您在 `axios` 和其他流行库中体验到的行为相同。如果您正在处理非标准 API,可以使用 `validateStatus` 选项自定义此行为。

使用自定义 validateStatus
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const customApi = createApi({
// Set the baseUrl for every endpoint below
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: `users`,
// Example: we have a backend API always returns a 200,
// but sets an `isError` property when there is an error.
validateStatus: (response, result) =>
response.status === 200 && !result.isError,
}),
}),
}),
})

向请求添加自定义超时

默认情况下,`fetchBaseQuery` 没有设置默认超时值,这意味着您的请求将一直处于挂起状态,直到您的 api 解决请求或达到浏览器的默认超时(通常为 5 分钟)。大多数情况下,这不是您想要的。使用 `fetchBaseQuery` 时,您可以设置 `baseQuery` 或单个端点的 `timeout`。当同时指定这两个选项时,端点值将优先。

设置超时值
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'

export const api = createApi({
// Set a default timeout of 10 seconds
baseQuery: fetchBaseQuery({ baseUrl: '/api/', timeout: 10000 }),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: `users`,
// Example: we know the users endpoint is _really fast_ because it's always cached.
// We can assume if its over > 1000ms, something is wrong and we should abort the request.
timeout: 1000,
}),
}),
}),
})