javascript - 动态决定使用哪种 Fetch 响应方法

标签 javascript fetch-api

我使用后端 API,它针对同一端点的不同请求返回不同的数据类型。虽然更合适的解决方案是统一返回的数据类型,但遗留问题、时间和缺乏测试对这个解决方案不利。

我正在集中我的 call 方法,以供需要调用端点的应用程序的其他部分使用。这个call方法实现了fetch。欲了解更多信息:

export default function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
  const url: string = buildUrl(parameter);
  const body: string | null = payload ? JSON.stringify(payload) : null;

  return fetch(url, {
    method,
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      Authorization: `Bearer ${getAuthToken()}`
    },
    body
  }).then(async (response) => {
    let body: IServerResponseObjectBody = {
      message: '',
      code: ''
    };

    if (response) {
      body = await response.json();
    }

    return {
      status: response.status,
      body
    };
  });
}

当我接收数据时,我使用 Response.json 方法对其进行解码。

if (response) {
  body = await response.json();
}

问题是有时我没有收到任何数据(当用户未经身份验证时 - 尽管这是一种边缘情况)或者服务器仅响应一个 bool 值。

在这种情况下,json() 执行会失败,因为我们没有处理 JSON 数据。

即:

FetchError: invalid json response body at http://localhost:4545/api/definition/isNameUnique/used%20name reason: Unexpected end of JSON input 

我想知道是否有比嵌套 try/catches 更干净的方法来确定从可用的解码方法中使用哪种解码方法: https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods

这感觉像是一个潜在的解决方案:https://developer.mozilla.org/en-US/docs/Web/API/Body#Properties但文档不太明确,并且缺乏如何使用它的示例。

最佳答案

在我看来,您想使用 text 来读取响应,然后查看生成的文本并决定要做什么。 大致:

const text = await response.text();
if (!text) {
    // no response, act accordingly
} else if (reBool.test(text)) {
    // boolean response, determine whether it's true or false and act on it
} else {
    // JSON response, parse it
    data = JSON.parse(text);
    // ...then use it
}

...其中 reBool 是一个正则表达式,用于测试服务器有时返回的 bool 值,例如 /^(?:true|false)$/i .

如果响应可能有空格,您可以 trim response.text() 的结果。

<小时/>

您可能还想做一些不相关的事情:

  1. 您没有检查是否有成功的响应(这是很多人都会犯的错误,所以我把很多人都写在了我原本贫乏的小博客上)。在使用 jsontext 等之前检查 response.ok

  2. async 函数作为回调传递给 then 没有多大意义。如果您要使用async,请尽早执行,将call设为async函数,然后使用await 贯穿整个正文,而不是混合你的隐喻......

解决这些问题并折叠在上面的主要答案中(您需要根据需要进行调整,IServerResponseObject需要更改,或者您需要对 bool 响应执行不同的操作):

const reBool = /^(?:true|false)$/i;

export default async function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
  const url: string = buildUrl(parameter);
  const body: string | null = payload ? JSON.stringify(payload) : null;

  const response = await fetch(url, {
    method,
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      Authorization: `Bearer ${getAuthToken()}`
    },
    body
  });
  const {status} = response;
  if (!response.ok) {
    throw new Error("HTTP error " + status); // Or `return {status};` or similar, but making it an error is useful
  }
  const text = (await response.text()).trim();
  let result = {status};
  if (!text) {
    // blank, act accordingly, perhaps:
    result.body = null;
  } else if (reBool.test(text)) {
    result.body = text === "true";
  } else {
    result.body = JSON.parse(text);
  }
  return result;
}

关于javascript - 动态决定使用哪种 Fetch 响应方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53762388/

相关文章:

javascript - 如何向 Facebook 分享按钮(通过 FB.ui 生成)添加计数器?

javascript - 获取 API - 返回的变量未定义

javascript - ChartJS : Get individual values minus another value in the custom legend

javascript - 关于 Fetch API 的一个小困惑

javascript - 在 ES6/Typescript 中链接 promises

javascript - 无法使用 Web Video Kit API 将视频发布到 Tiktok

javascript - Chrome : to play a video that is being downloaded via fetch/XHR

javascript - 导航链接不起作用

javascript - AngularJS/javascript 将日期字符串转换为日期对象

javascript - 平滑滚动到 ID