"菜谱汇"把下厨房、美食杰、豆果的菜谱聚到一处,用户搜"川菜"能一次看到全网结果。
三个源并发请求,合并去重后按评分排序
每个源的鉴权方式不同,得隔离管理
菜谱封面图下载到本地缓存,要显示进度条
用原生 @ohos.net.http 的话,三套鉴权逻辑、三次回调嵌套、三次文件流处理——全是重复代码。
| 需求 | 原生 http | @ohos/axios | | --- | --- | --- | | 三源并发 | 手写 Promise.all + 回调 | axios.all 一行 | | 各源独立鉴权 | 每次手动加 header | 多实例拦截器 | | 错误兜底 | 每个请求各写 catch | 响应拦截器统一 | | 下载进度 | 手写流式处理 | onDownloadProgress | | 某源挂了要容错 | 手写 | Promise.allSettled |
import
axios, {
AxiosResponse
}
from
'@ohos/axios'
interface
Recipe
{
id
:
string
;
title
:
string
;
cover
:
string
;
rating
:
number
}
const
srcA = axios.
create
({
baseURL
:
'https://api.xiachufang.com'
,
timeout
:
10000
})
srcA.
interceptors
.
request
.
use
(
(
c
) =>
{ c.
headers
[
'Authorization'
] =
'Bearer '
+ tokenA;
return
c })
const
srcB = axios.
create
({
baseURL
:
'https://api.meishij.com'
,
timeout
:
10000
})
srcB.
interceptors
.
request
.
use
(
(
c
) =>
{ c.
params
= { ...c.
params
,
api_key
: tokenB };
return
c })
const
srcC = axios.
create
({
baseURL
:
'https://api.douguo.com'
,
timeout
:
10000
})
srcC.
interceptors
.
request
.
use
(
(
c
) =>
{ c.
headers
[
'X-Sign'
] =
sign
(c.
url
);
return
c })鉴权逻辑各写一次,之后再怎么加请求都不用管——这是拦截器最省心的地方。
某个源挂了不该让整个页面白屏,用 allSettled :
async
function
fetchRecipes
(
category:
string
):
Promise
<
Recipe
[]> {
const
url =
`/recipes?category=
${category}
`
const
results =
await
Promise
.
allSettled
([
srcA.
get
<
Recipe
[],
AxiosResponse
<
Recipe
[]>,
null
>(url),
srcB.
get
<
Recipe
[],
AxiosResponse
<
Recipe
[]>,
null
>(url),
srcC.
get
<
Recipe
[],
AxiosResponse
<
Recipe
[]>,
null
>(url),
])
const
all
:
Recipe
[] = []
results.
forEach
(
(
r, i
) =>
{
if
(r.
status
===
'fulfilled'
) all.
push
(...r.
value
.
data
)
else
console
.
warn
(
`源
${i}
失败已跳过:
${r.reason}
`
)
})
const
seen =
new
Set
<
string
>()
return
all.
sort
(
(
a, b
) =>
b.
rating
- a.
rating
).
filter
(
(
r
) =>
{
if
(seen.
has
(r.
title
))
return
false
seen.
add
(r.
title
);
return
true
})
}import
fs
from
'@ohos.file.fs'
async
function
downloadCover
(
recipe: Recipe
):
Promise
<
string
> {
const
filePath =
getContext
(
this
).
cacheDir
+
`/cover_
${recipe.id}
.jpg`
try
{ fs.
accessSync
(filePath);
return
filePath }
catch
(e) {
}
const
res =
await
axios.
get
<
ArrayBuffer
,
AxiosResponse
<
ArrayBuffer
>,
null
>(recipe.
cover
, {
responseType
:
'array_buffer'
,
onDownloadProgress
:
(
e
) =>
{
this
.
percent
= e?.
total
?
Math
.
ceil
(e.
loaded
/ e.
total
*
100
) :
0
},
})
const
file = fs.
openSync
(filePath, fs.
OpenMode
.
CREATE
| fs.
OpenMode
.
READ_WRITE
)
fs.
writeSync
(file.
fd
, res.
data
)
fs.
closeSync
(file)
return
filePath
}设了 onDownloadProgress 之后,请求会自动切到流式模式,此时 response.performanceTiming 会是 undefined 。
如果你既想要进度条又想要性能计时数据,两者拿不到一起——按业务优先级选一个。菜谱列表页要进度条,就别指望同时拿 DNS/TCP 耗时。
聚合类 App 的痛点从来不是"发请求",而是 多个数据源的差异化处理 。 @ohos/axios 的多实例拦截器把鉴权、错误、日志这些横切关注点全收敛掉,业务代码只剩下"拉数据、合并、渲染"。
再加上 allSettled 的容错和现成的下载进度回调,一个菜谱聚合页半天就能写完。
转载声明:本文为转载整理,原文版权归原作者及原站点所有。
原文来源:Juejin HarmonyOS
原文作者:OH_TPC;如有侵权,请联系管理员删除。