Javascript Fetch API太快;在第二个HTTP(fetch api)请求之前完成。

问题描述 投票:2回答:1

我有2个使用Javascript中Fetch API的HTTP请求。我的主要语言是Java,但我的任务是一个前端项目,所以我不确定是否有一个简单的解决方案。我的问题是,第一个调用(击中一个随机的服务器)击中的是一个外部端点,这个端点与第二个外部端点不同(这个端点在Azure上),但第二个端点依赖于第一个端点。基本上,第一个端点是一个POST请求,在Azure网站(IoT hub)上创建populates一个objectIoT设备。因此,第二个请求不能真正做任何事情(在这种情况下patch),直到设备在网站上显示出来。我注意到它通常需要几秒钟,比如1-5秒才会出现。

我的Fetch API看起来是这样的。

fetch('https://first-API-endpoint-on-random-server.com/creates-thing-on-Azure', {
  method: 'POST',
  headers: myHeaders,
  body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
  console.log('Success:', data);

  // Beginning of nested Fetch
  return fetch('https://second-DIFFERENT-API-endpoint-on-azure.com/tries-to-edit-thing-on-Azure', {
      method: 'PATCH',
      headers: myHeaders,
      body: JSON.stringify(data),
    })
    .then(response => response.json())
    .then(data => {
      console.log('Success:', data);
    })
    .catch((error) => {
      console.error('Error:', error);
    });
})

因此,基本上你点击一个按钮 在我的网站的UI和它应该运行这个onClick函数 和创建populate对象IoT设备 在Azure的第1个Fetch API调用,然后第2个Fetch API调用 应该是 "PATCH "它或编辑JSON。

第一个API调用 始终 作品 但问题是第二个API调用似乎总是因为404 "设备未找到 "错误而失败,因为我认为第一个调用完成得太快,然后第二个调用试图修补网站上根本不存在的东西. 我的解决方法是将API调用分为两个不同的点击事件,这样就解决了这个问题,因为当用户点击第二个按钮的时候,第二个Fetch API调用PATCH 平时 总是成功的。

我真的想把它们合并成一个Function,让用户永远不知道PATCH eventhttp调用。我如何才能让这第二个Fetch真正发挥作用?

我可以提供你想要的任何细节,请你提供,谢谢你。

javascript azure fetch-api
1个回答
1
投票

它看起来像服务器的 200 初始请求的响应表明请求已被正确处理,但不表明资源已在 Azure 上创建。在服务器响应后的一段时间内,资源在 Azure 上被创建,但客户端的第二个请求是在一段时间内提出的。之前 资源已被创建。这里是一个可能的请求和响应序列的时间线。

  1. 客户端(Web浏览器)向服务器发出第1个(POST)请求。
  2. 服务器收到请求后,向 Azure 提出创建资源的请求,然后返回一个 200 表示该请求已被处理。此时,Azure 已收到该请求,并可能开始创建资源。
  3. 客户端(Web 浏览器)收到了 200 的响应,并继续进行第二个 (PATCH) 请求。此时,Azure可能正在创建资源的过程中,但还没有完成创建,因此它返回一个 404.

这个问题可以在后端解决,例如,让服务器等待在 Azure 上创建资源,然后再以一个 "我 "的名字来响应。200 客户端。如果无法实现,在客户端可以采取两条线的行动,分别或组合。

  • 等到固定的时间后再提出第二个请求,在收到请求之后 200 的第一个请求的时间。由于我们没有从后端得到关于资源何时被创建的指示,我们可以选择一个任意的时间量。下面是一个例子,我们等待1秒。
function createResource(data) {
  return fetch('https://first-API-endpoint-on-random-server.com/creates-thing-on-Azure', {
    method: 'POST',
    headers: myHeaders,
    body: JSON.stringify(data),
  })
}

function updateResource(data) {
  return fetch('https://second-DIFFERENT-API-endpoint-on-azure.com/tries-to-edit-thing-on-Azure', {
     method: 'PATCH',
     headers: myHeaders,
     body: JSON.stringify(data),
  })
}

function createAndUpdateResource(data) {
  return new Promise((resolve, reject) => {
    return createResource(data)
      .then(res => res.json())
      .catch(reject)
      .then(resourceData => {
        setTimeout(() => {
          // do we pass data or resourceData data to the PATCH request?
          updateResource(resourceData)
            .then(res => res.json())
            .then(resolve)
            .catch(reject)
          });
        }, 1000);
      });
  });
}

createAndUpdateResource({ name: "abc" })
  .then(res => {
    console.log("success:", res);
  })
  .catch(err => {
    console.log("error: ", err.message);
  });

  • 在第二个请求中使用重试机制。在得到404的时候,我们可以对同一个请求有一些有限的重试次数。这可以与上面描述的超时方法相结合。下面是一个带重试的实现例子。
function withRetry(apiCall, retryCount, timeoutMS, statusForRetry) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      apiCall()
        .then(res => {
          if (!res.ok) {
            if (res.status === statusForRetry && retryCount > 0) {
              return withRetry(
                apiCall,
                retryCount - 1,
                timeoutMS,
                statusForRetry
              );
            }
            reject(new Error("couldn't update"));
          }
          return res.json();
        })
        .then(resolve)
        .catch(reject);
    }, timeoutMS);
  });
}

function createAndUpdateResource2(data) {
  return new Promise((resolve, reject) => {
    return createResource(data)
      .then(res => res.json())
      .then(resourceData =>
        withRetry(
          () => updateResource(resourceData),
          3, // 3 retries
          1000, // wait 1 second
          404 // retry on 404
        )
      )
      .then(resolve)
      .catch(reject);
  });
}

© www.soinside.com 2019 - 2024. All rights reserved.