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

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

菜谱数据分散在三个平台,要同时拉取、合并、按评分排序。麻烦的是三个源的鉴权方式还不一样:一个用 Header Token,一个用 Query 参数,一个要签名。@ohos/axios 的多实例 + 拦截器,让每个源的鉴权各管各的,业务代码一行都不用重复。
📦 仓库地址 | ohpm install @ohos/axios


场景

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

三件事要做:

  1. 三个源并发请求,合并去重后按评分排序
  2. 每个源的鉴权方式不同,得隔离管理
  3. 菜谱封面图下载到本地缓存,要显示进度条

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


为什么是 axios

需求 原生 http @ohos/axios
三源并发 手写 Promise.all + 回调 axios.all 一行
各源独立鉴权 每次手动加 header 多实例拦截器
错误兜底 每个请求各写 catch 响应拦截器统一
下载进度 手写流式处理 onDownloadProgress
某源挂了要容错 手写 Promise.allSettled

关键实现

每个源一个实例,鉴权互不干扰

typescript 复制代码
import axios, { AxiosResponse } from '@ohos/axios'

interface Recipe { id: string; title: string; cover: string; rating: number }

// 源 A:Token 放 Header
const srcA = axios.create({ baseURL: 'https://api.xiachufang.com', timeout: 10000 })
srcA.interceptors.request.use((c) => { c.headers['Authorization'] = 'Bearer ' + tokenA; return c })

// 源 B:Token 放 Query
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 })

// 源 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:

typescript 复制代码
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
  })
}

封面图下载带进度

typescript 复制代码
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 的容错和现成的下载进度回调,一个菜谱聚合页半天就能写完。

相关推荐
老陈说编程1 小时前
2. 鸿蒙(HarmonyOS)超级终端与生态
华为·harmonyos
2501_919749033 小时前
华为鸿蒙免费时钟工具—小羊时钟
华为·harmonyos
aqi0014 小时前
鸿蒙版本的电子书阅读APP开放源码啦
android·华为·ai编程·harmonyos·鸿蒙
xq952718 小时前
HDC Assistant 插件横空出世
harmonyos
OH_TPC1 天前
【鸿蒙优选三方库】@ohos/aki:一行代码让 ArkTS 调 C++
harmonyos
wenyiyiyiyiyi1 天前
我用鸿蒙 ArkTS 写了个自己天天用的备忘录:待办、课表和长期目标,全塞进一块桌面卡片
harmonyos
承渊政道1 天前
鸿蒙设备远控电脑实测:ToDesk蓝牙键鼠、双模式鼠标、跨端剪贴板,远控电脑更顺手了
计算机外设·电脑·harmonyos·远程工作·todesk
CV工程师丁Sir1 天前
ArkWeb 手记 04|DevTools 调试与缓存清理
java·spring·缓存·harmonyos
程序猿追2 天前
HarmonyOS 6 上做个极简浏览器:Web 组件 + 前进后退 + 加载进度
前端·华为·harmonyos