我对React或JavaScript没有多少经验。我正在创建一个从API获取时间序列数据的简单应用程序。该数据用于绘制折线图(React Apex Chart)。都好。
问题是API响应大小限制为最多2,000条记录,有时我们需要更多数据。
响应大小限制为最多2,000条记录。如果必须返回更多记录,则响应头包含带有URI的链接头,以获取下一组记录:
链接:https://apiurl;为rel = “下一步”
我的代码获取api数据,对其进行排序并将其发送到子组件(Chart)。
FetchAPI(){
fetch(https://MYURLHERE?from=FROMDATE&to=TODATE)
.then(response => response.json())
.then(data => this.setState({
kWhData: data.map((kWh) => kWh._kWh),
TimeStampData: data.map((time) => time._time),
loading: false
}))
.catch(error => console.log('Fetching failed', error))
}
Link header: link →<https://MYURLHERE?from=FROMDATE&limit=2000&to=TODATE>; rel="next">
我知道解决方案可能是某种分页但我不完全理解这个概念。我搜索了类似的问题但没有运气。
希望有人能为我提供帮助,提示或代码。
我不知道您正在使用什么API,但听起来您需要做的就是从头部获取下一组结果的URL,然后向其发出请求。
在返回response.json()
之前,您可以使用response.headers.get()
访问标题。因此,您可以执行类似let nextPage = response.headers.get('Link')
的操作,将完整的Link标头作为字符串。然后,您可以在分号处拆分它,并使用第一部分作为下一个分页请求的URL。
如果我正确理解了这个问题,我会在你的FetchApi函数中添加一个变量,这样它就可以查询你的初始API URL或后续页面的URL:
FetchAPI(requestURL){
// Fetch function here
}
这个想法是,这个函数可以迭代地调用自己,结果的'next'页面的url作为每个调用的参数传递,直到响应指示已经检索了所有数据。
所以你的初始调用是FetchAPI('https://MYURLHERE?from=FROMDATE&to=TODATE')。
如果达到速率限制,您可以再添加一行来再次调用此函数。例如:
FetchAPI(requestURL){
fetch(requestURL)
.then(response => {
if(response.dataLimit == true){ // Or however this is expressed
// Concat new data with any already retrieved
this.FetchAPI(nextPageUrl) // Get the URL of the next page and call FetchAPI again with this e.g https://MYURLHERE?from=FROMDATE&limit=2000&to=TODATE
} else {
// Otherwise stop and do something else now that you have a complete set of data
}
})
}
值得一提的是,这是未经测试的代码,但希望足以让原则得到解决。
此外,如果API具有请求率限制,例如1秒,您可以在函数再次调用之前添加延迟,但显然这会影响检索所有数据的总时间。
谢谢你们。我得到了两个答案的混合工作。
我不知道这是一个好方法,还是“正确”的方法。也许你们可以给我一些反馈?
setTimeout仅用于测试,但我认为我需要至少1000?
获取API需要凭证/标头。
FetchAPI(requestURL) {
fetch(requestURL, {
credentials: 'include',
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"x-xsrf-token": this.myXRSFToken,
"origin": `${window.location.protocol}//${window.location.host}`
}
})
.then(response => {
let Responseheader = response.headers.get('Link')
response.json()
.then(data => this.setState({
TestData: this.state.TestData.concat(data)
}))
if (Responseheader){
let nextPageUrl = Responseheader.match(/\bhttps?:\/\/\S+Z/gi)
setTimeout(() => {
this.FetchAPI(nextPageUrl)
}, 2000);
} else {
console.log('Done fetching API')
this.setState({
loading: false
})
return
}
})
.catch(error => console.log('Fetching failed', error))
}