当前位置:首页>鸿蒙APP>鸿蒙网络请求全栈封装|统一拦截器、Token自动续期、异常重试、弱网缓存、全局报错处理

鸿蒙网络请求全栈封装|统一拦截器、Token自动续期、异常重试、弱网缓存、全局报错处理

  • 2026-10-10 22:56:45
鸿蒙网络请求全栈封装|统一拦截器、Token自动续期、异常重试、弱网缓存、全局报错处理

一、前言:为什么项目必须统一封装网络?

绝大多数鸿蒙新手项目的网络写法:每个页面单独 fetch / http 请求。

这种写法上线必出一堆隐性Bug:

  • 每个接口都要重复写 loading、异常提示、超时配置

  • Token 过期不自动刷新,用户频繁掉线重登

  • 弱网、404、500、后端报错无统一处理

  • 快速点击多次触发同一接口,造成重复提交

  • 页面销毁后接口还在回调,引发页面销毁报错、内存泄漏

  • 无缓存策略、无重试策略、用户体验差

商用鸿蒙项目标准:全网统一封装 + 全局拦截器 + 自动Token续期 + 防抖节流 + 自动重试 + 离线缓存。

本篇给企业级可直接上线的完整网络架构,一套代码通用于所有鸿蒙商用、政企、上架项目,可直接写进简历、面试满分、项目直接落地。

二、企业级网络架构分层(标准四层)

商用项目必须分层,禁止所有代码堆在页面。

四层架构(从上到下)

  1. API层:统一管理所有接口地址、请求参数(只定义,不处理逻辑)

  2. Request请求层:统一请求方式、统一参数、统一返回结构

  3. Interceptor拦截层:请求拦截、响应拦截、Token处理、错误统一收口

  4. Cache/Retry工具层:缓存策略、重试策略、防抖、取消请求

优势:改一处、全局生效,维护成本极低,全网行为统一。

三、核心能力清单(本篇全部落地)

  • 全局统一请求头、超时时间、Content-Type

  • 请求拦截:自动携带Token、统一参数加密

  • 响应拦截:统一解析后端格式、全局报错提示

  • Token过期自动续期、无感刷新(高薪核心)

  • 重复请求防抖、接口节流

  • 页面销毁自动取消请求(杜绝内存泄漏)

  • 弱网/超时自动重试机制

  • 离线缓存、兜底数据策略

  • 统一Loading、统一Toast报错、业务错误码统一处理

四、完整代码实战(可直接商用)

4.1 环境配置与常量定义 config

// config/HttpConfig.etsexport default class HttpConfig {  // 正式/测试地址  public static BASE_URL: string = "https://xxx.com/api"  // 超时时间 10s  public static TIME_OUT: number = 10000  // 重试次数  public static RETRY_COUNT: number = 2  // 重试间隔  public static RETRY_DELAY: number = 800}

4.2 全局Token管理(结合AppStorage)

// store/TokenStore.etsimport AppStorage from '@ohos.appstorage'export class TokenUtil {  // 获取Token  staticgetToken(): string {    return AppStorage.get('token') || ''  }  // 设置Token  staticsetToken(token: string) {    AppStorage.setOrCreate('token', token)  }  // 清除Token  staticclearToken() {    AppStorage.delete('token')  }}

4.3 核心网络拦截器封装(重点)

// utils/HttpRequest.etsimport http from '@ohos.net.http'import promptAction from '@ohos.promptAction'import HttpConfig from '../config/HttpConfig'import { TokenUtil } from '../store/TokenStore'// 存储当前请求队列(用于取消重复请求)const pendingRequest: Set<string> = new Set()// 基础请求封装async function request<T>(  url: string,  method: http.RequestMethod,  data?: Object,  header?: Object): Promise<T> {  // 1. 请求唯一key防抖  const reqKey = url + JSON.stringify(data)  if (pendingRequest.has(reqKey)) {    return Promise.reject("重复请求已拦截")  }  pendingRequest.add(reqKey)  // 2. 创建请求实例  const httpRequest = http.createHttp()  // 3. 统一请求头  const headers: Object = {    'Content-Type': 'application/json;charset=UTF-8',    'token': TokenUtil.getToken(),    ...header  }  // 4. 请求配置  const option: http.HttpRequestOptions = {    method: method,    header: headers,    readTimeout: HttpConfig.TIME_OUT,    connectTimeout: HttpConfig.TIME_OUT,    extraData: data  }  try {    // 5. 发起请求    const res = await httpRequest.request(HttpConfig.BASE_URL + url, option)    pendingRequest.delete(reqKey)    httpRequest.destroy()    // 6. 统一解析后端返回格式    const result: any = JSON.parse(res.result.toString())    // 7. 业务状态码拦截    if (result.code === 200) {      return result.data    } else if (result.code === 401) {      // Token过期触发续期      return refreshToken(() => request(url, method, data, header))    } else {      promptAction.showToast({ message: result.msg || "请求失败" })      return Promise.reject(result)    }  } catch (err) {    pendingRequest.delete(reqKey)    httpRequest.destroy()    promptAction.showToast({ message: "网络异常,请检查网络" })    return Promise.reject(err)  }}

4.4 高级核心:Token 无感自动续期

企业项目最大痛点:用户操作中途Token过期,直接掉线。

解决方案:401拦截 - 自动刷新Token - 重发失败请求 - 用户无感知。

// 全局锁:防止多次同时刷新let isRefreshing: boolean = falseasync function refreshToken(callback: Function) {  if (isRefreshing) return  isRefreshing = true  try {    // 1. 请求刷新Token接口    const res = await request<any>('/user/refresh', http.RequestMethod.POST, {      refreshToken: TokenUtil.getToken()    })    // 2. 保存新Token    TokenUtil.setToken(res.token)    // 3. 重发之前失败的接口    return callback()  } catch (e) {    // 刷新失败 → 清空登录态、跳转登录    TokenUtil.clearToken()    promptAction.showToast({ message: "登录已过期,请重新登录" })  } finally {    isRefreshing = false  }}

4.5 防抖、节流、取消重复请求

上面 pendingRequest 队列已经实现:

  • 短时间相同参数、相同地址请求直接拦截

  • 解决按钮连击、列表多次刷新、重复提交表单

4.6 自动重试机制(弱网适配)

政企设备、工控、弱网环境必备。

async function retryRequest<T>(fn: ()=>Promise<T>, count = 0):Promise<T> {  try {    return await fn()  } catch (e) {    if(count < HttpConfig.RETRY_COUNT){      // 延迟重试      await new Promise(res=>setTimeout(res, HttpConfig.RETRY_DELAY))      return retryRequest(fn, count + 1)    }    return Promise.reject(e)  }}

4.7 封装 GET / POST 统一方法

export function get<T>(url: string, data?: Object): Promise<T> {  return retryRequest(()=> request(url, http.RequestMethod.GET, data))}export function post<T>(url: string, data?: Object): Promise<T> {  return retryRequest(()=> request(url, http.RequestMethod.POST, data))}

4.8 统一API接口管理

// api/IndexApi.etsimport {get, post} from '../utils/HttpRequest'// 首页数据export const getHomeData = (params: any) => get('/home/data', params)// 登录export const loginApi = (params: any) => post('/user/login', params)// 提交表单export const submitFormApi = (params: any) => post('/form/submit', params)

4.9 页面销毁取消请求(防泄漏终极方案)

在页面 aboutToDisappear 清空队列,彻底解决页面销毁接口还在回调的闪退、报错、内存泄漏问题。

aboutToDisappear(){  pendingRequest.clear()}

五、离线缓存策略(商用体验加分)

弱网/无网场景,优先展示旧缓存,网络恢复自动更新。

实现思路:

  1. 接口请求成功后,将数据缓存至 Preferences

  2. 请求失败/超时,优先读取本地缓存兜底

  3. 支持缓存过期时间配置

极大提升政企设备、户外弱网场景用户体验。

六、面试满分答题模板(网络封装必背)

面试官:你项目的网络层是怎么封装的?

标准满分回答:

我在项目中搭建了四层企业级网络架构,统一收口全网请求。通过请求拦截器自动携带Token、统一请求头和超时配置;响应拦截器统一解析返回格式、全局处理报错信息、统一Toast提示。

针对Token过期问题,我实现了401无感自动续期机制,加锁防止并发刷新,续期成功自动重发失败请求,用户全程无感知。

同时做了请求防抖与节流,通过请求队列拦截重复接口,解决按钮连击和重复提交;针对弱网环境实现自动重试策略;页面销毁清空请求队列,彻底杜绝因接口残留导致的内存泄漏和页面报错。并且增加了离线缓存兜底,大幅提升弱网场景体验。

七、简历高薪写法(直接复制)

独立搭建企业级四层网络架构,封装统一请求、拦截器、异常处理;实现Token自动续期、无感刷新登录态;通过请求队列防抖节流解决重复提交问题;适配弱网自动重试与离线缓存兜底;页面生命周期绑定请求销毁,解决网络残留导致的内存泄漏,全网行为统一规范,提升项目稳定性与用户体验。

八、总结

网络层封装是区分初级和中级鸿蒙工程师的核心标杆。只会调接口是初级,会架构、会拦截、会续期、会防抖、会治理网络问题,才是商用高薪标准。

最新文章

随机文章