ITPub博客

首页 > 应用开发 > .net > 技术解读:HarmonyOS APP开发---"菜谱汇"美食菜谱App,需要用到这个库

技术解读:HarmonyOS APP开发---"菜谱汇"美食菜谱App,需要用到这个库

.net 作者:Flow_Official 时间:2026-10-12 17:34:38 0 删除 编辑

场景

"菜谱汇"把下厨房、美食杰、豆果的菜谱聚到一处,用户搜"川菜"能一次看到全网结果。

  • 三个源并发请求,合并去重后按评分排序

  • 每个源的鉴权方式不同,得隔离管理

  • 菜谱封面图下载到本地缓存,要显示进度条

用原生 @ohos.net.http 的话,三套鉴权逻辑、三次回调嵌套、三次文件流处理——全是重复代码。

为什么是 axios

| 需求 | 原生 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

原创地址:https://juejin.cn/post/7694845307458404402

原文作者:OH_TPC;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2022-08-02

  • 博文量
    36
  • 访问量
    32565