我有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真正发挥作用?
我可以提供你想要的任何细节,请你提供,谢谢你。
它看起来像服务器的 200
初始请求的响应表明请求已被正确处理,但不表明资源已在 Azure 上创建。在服务器响应后的一段时间内,资源在 Azure 上被创建,但客户端的第二个请求是在一段时间内提出的。之前 资源已被创建。这里是一个可能的请求和响应序列的时间线。
200
表示该请求已被处理。此时,Azure 已收到该请求,并可能开始创建资源。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);
});
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);
});
}