HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)

news2025/1/12 1:03:10

系列文章目录

HarmonyOS Next 系列之省市区弹窗选择器实现(一)
HarmonyOS Next 系列之验证码输入组件实现(二)
HarmonyOS Next 系列之底部标签栏TabBar实现(三)
HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)


文章目录

  • 系列文章目录
  • 前言
  • 一、实现设计
  • 二、代码实现
    • 1.http请求工具类request.ets
    • 2.token持久化存取
    • 3.页面使用


前言

HarmonyOS Next(基于API11)封装一个http请求工具类,自动拦截token失效跳转登录页,以及token持久化存取方案。


一、实现设计

  • 对于接口请求我们最关心两个东西,一个是请求参数另一个是接收服务器返回的数据

(1)请求参数最常设置的有:

请求链接url、请求方式method(post,get等)、请求参数data、请求数据类型Content-Type、登录凭证token

其中token可从本地持久化读取无需传入,剩下四个可设计为动态传参

//接口入参数据类型
interface RequestParams {
  url: string //请求链接
  method?: http.RequestMethod //请求方式
  data?: Object //请求额外数据
  headerContentType?: string //请求数据类型
}

(2)返回数据一般是个对象 常见固定字段有:

code:状态码 ,message:接口响应说明 ,data:返回数据

故接口返回数据类型可定义为:

//接口请求返回数据类型
interface ResponseResult {
  code: number //状态码
  message: string //处理信息
  data: Object | null //返回数据
}

ps:根据实际需要也可按需添加字段

对于返回数据code状态码一般定义:
1、200为请求成功
2、401 token失效(无效或缺失)
3、其他情况归为请求失败

所以对于接口返回数据可根据code值分三种情况处理例如:

if(code==200){//请求成功
   //返回数据
}
else if(code==401){//token失效
 //拦截跳转到登录页
 router.replaceUrl({
      url: "/pages/login"
  })
}
else{//请求失败
 
}

ps:当然状态码也可根据实际定义修改

  • Token持久化存储
    为了配合登录方案实现,方便在EntryAbility使用token,我们这里选择了Preferences作为存储方案。

最后,熟悉web开发的同学都知道web项目中习惯把接口定义放置在api文件夹下统一管理,然后在页面引入使用,再此沿用该开发习惯,方便后期维护。

二、代码实现

目录结构:
在这里插入图片描述

1.http请求工具类request.ets

封装一个http请求工具类文件,默认导出一个请求函数返回Promise(接口返回数据)

utils/request.ets

import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
import promptAction from '@ohos.promptAction'
import { getToken } from './index'
import router from '@ohos.router';

//baseURL接口域名
const BASEURL: string = "https://xxxxxxx.com"
//登录页路由
const LOGINPAGEURL = 'pages/common/login'

//接口入参数据接口
interface RequestParams {
  url: string
  method?: http.RequestMethod
  data?: Object
  headerContentType?: string
}


//接口请求返回数据类
class ResponseResult {
  code: number //状态码
  message: string //处理信息
  data: Object | null //返回数据

  constructor(code?: number, message?: string, data?: Object | null | undefined) {
    this.code = code ?? 0
    this.message = message ?? ''
    this.data = data ?? null
  }
}

/**
 *
 * @param params:接口请求参数(object类型)
 * {
 *  url :请求连接
 *  method :请求方法
 *  data :请求数据
 *  headerContentType :请求头发送的数据格式
 * }
 * @returns Promise<ResponseResult>
 */
export default function request(params: RequestParams): Promise<ResponseResult> {
  return new Promise(async (resolve: (res: ResponseResult) => void, reject: (res: ResponseResult | string | BusinessError | http.HttpResponse) => void) => {
    //请求头contentType
    let contentType: string = params.headerContentType || 'application/json' //默认提交数据类型为application/json
    //请求数据data
    let requestData: Object | undefined = params.data;
    //application/x-www-form-urlencoded类型参数处理成key&value形式
    if (contentType === 'application/x-www-form-urlencoded') {
      if (typeof params.data === 'object') {
        requestData = Object.entries(requestData as object).reduce((prev: string, cur: Array<Object>) => {
          return (prev && `${prev}&`) + `${cur[0]}=${cur[1]}`
        }, '')
      }
    }
    //从本地存储获取token
    let token: string = await getToken()
    let httpRequest = http.createHttp();
    httpRequest.request(BASEURL + params.url, {
      method: params.method ?? http.RequestMethod.GET, //默认get方法
      header: {
        'Content-Type': contentType,
        token
      },
      extraData: requestData,
      readTimeout: 30000,
      connectTimeout: 30000
    }, (err: BusinessError, data: http.HttpResponse) => {
      if (!err) {
        //请求成功
        if (data.responseCode === 200) {
          let res: ResponseResult = JSON.parse(`${data.result}`);
          let response = new ResponseResult(res.code, res.message, res.data)
          //状态码code=200表示请求成功,状态码可根据实际接口文档修改
          if (res.code === 200) {
            resolve(response);
          }
          //状态码code=401表示token失效,状态码可根据实际接口文档修改
          else if (res.code === 401) { //跳转登录页
            router.clear() //清空历史页面
            //跳转到登录页
            router.replaceUrl({
              url: LOGINPAGEURL
            })
          }
          //其他情况接口异常
          else {
            showToast(response.message)
            reject(response);
          }
        }
        //请求失败
        else {
          showToast()
          reject(data)
        }

      }
      //请求失败
      else {
        showToast(err.message)
        reject(err)
      }
      // 取消订阅HTTP响应头事件
      httpRequest.off('headersReceive');
      // 当该请求使用完毕时,主动销毁该JavaScript Object。
      httpRequest.destroy();
    })
  })
}

//弹窗提示
const showToast = (message?: string) => {
  promptAction.showToast({
    message: message || '请求出错',
    duration: 2000
  })
}

说明:
(1)定义了接口前缀(域名+端口号?+通用匹配符?) BASEURL:可根据实际修改
(2)定义了登录页面路由 LOGINPAGEURL token失效跳转使用 :可根据实际修改
(3)函数request入参是个对象,包含如下属性

{
     url :请求连接
     method ?:请求方法
     data ?:请求数据
     headerContentType? :请求头发送的数据格式
  }

method不传默认get方式,headerContentType 不传默认application/json
当contetn-type为 “application/x-www-form-urlencoded” , data请求参数 自动处理成key&value形式

(4)请求结果返回Promise

  {
  code: number //状态码
  message: string //处理信息
  data: Object | null //返回数据
}

当code=200,promise返回接口数据
当code=401 token失效自动跳转登录页,
当code其他值表示请求失败,showToast显示接口message字段文字

(5)请求头默认添加token数据,从本地存储读取

2.token持久化存取

(1)entryability/EntryAbility.ets

import dataPreferences from '@ohos.data.preferences';
....
....
....
 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
  
    globalThis.getPreferences = () => {
      let preferences: Promise<dataPreferences.Preferences> = dataPreferences.getPreferences(this.context, "appStore")
      return preferences
    }
  }

EntryAbility. onCreate周期函数内给全局变量globalThis添加getPreferences 属性方法,方便快速获取Preferences实例 ,添加到globalThis是为了后续页面开发或者工具类使用Preferences

(2)utils/index.ets 工具类

import dataPreferences from '@ohos.data.preferences';
//获取token
export const getToken: Function = async () => {

  try {
    let preferences: dataPreferences.Preferences = await globalThis.getPreferences()
    return preferences.getSync('token', '')
  }
  catch (e) {
  }
  return ''
}

//设置token并本地持久化存储
export const setToken: Function = async (value: string) => {
  try {
    let preferences: dataPreferences.Preferences = await globalThis.getPreferences()
    preferences.putSync('token', encodeURIComponent(value))
    await preferences.flush()
  }
  catch (e) {
    console.log(JSON.stringify(e), 'e')
  }
}

在工具类index.ets封装2个方法(getToken,setToken),分别为获取token值和设置token值,其中setToken在登录成功获取到token值时候调用存入本地持久化

3.页面使用

在这里插入图片描述
新建api文件夹、新建与页面同名的ets文件写入api定义
api/home.ets


import http from '@ohos.net.http'
import request from '../utils/request'

class params{
    storeId:string=''
}
//获取首页数据
export function getHomeData(data:params){
    return request({
        url:"/api/store/home",
        method:http.RequestMethod.POST, //不传默认GET
        data,
        headerContentType:'application/x-www-form-urlencoded' //不传默认application/json
    })
}



//其他接口
export function xxxxx(data:params){
    return request({
        url:"xxxxxxxx",
        data,
    })
}
......
......
......

页面引入
pages/Home.ets

import {getHomeData} from "../api/home"
@Entry
@Component
struct Home{
     aboutToAppear(): void {
         getHomeData({
          storeId:'17815455885'
        }).then(res=>{
           console.log(JSON.stringify(res),'接口返回数据')
        }
     }
}

运行结果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1820130.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

家用洗地机排行榜前十名:2024十大王牌机型精准种草

最近很多人都在问我洗地机相关的问题&#xff0c;不愧是改善家庭生活品质的“三神器”之一。洗地机依靠其清洁力和清洁效率吸引了越来越多的平时需要做家务人群的兴趣&#xff0c;为了解答大家关于洗地机的各种疑问&#xff0c;我把市面上目前非常火爆的洗地机型号和参数都进行…

探索未来通信的新边界:AQChat一款融合AI的在线匿名聊天

探索未来通信的新边界&#xff1a;AQChat一款融合AI的在线匿名聊天 在数字时代&#xff0c;即时通讯变得无处不在&#xff0c;但隐私和性能仍旧是许多用户和开发者关注的焦点。今天&#xff0c;我要介绍一个开创性的开源项目 —— AQChat&#xff0c;它不仅重定义了在线匿名聊…

Spring IoC注解

一、回顾反射机制 反射的调用三步&#xff1a;1&#xff09;获取类。2&#xff09;获取方法。3&#xff09;调用方法 调用方法&#xff1a;调用哪个对象&#xff0c;哪个方法&#xff0c;传什么参数&#xff0c;返回什么值。 方法&#xff08;Do&#xff09;类&#xff1a; …

eFuse电子保险丝,需要了解的技术干货来啦

热保险丝作为一种基本的电路保护器件&#xff0c;已经成功使用了150多年。热保险丝有效可靠、易用&#xff0c;具有各种不同的数值和版本&#xff0c;能够满足不同的设计目标。然而&#xff0c;对于寻求以极快的速度切断电流的设计人员来说&#xff0c;热保险丝不可避免的缺点就…

【高校科研前沿】北京大学赵鹏军教授团队在Nature Communications发文:揭示城市人群移动的空间方向性

文章简介 论文名称&#xff1a;Unravelling the spatial directionality of urban mobility 第一作者及单位&#xff1a;赵鹏军&#xff08;教授|第一作者|北京大学&#xff09;&王浩&#xff08;博士生|共同一作|北京大学&#xff09;; 通讯作者及单位&#xff1a;赵鹏军…

SCI二区|鲸鱼优化算法(WOA)原理及实现【附完整Matlab代码】

目录 1.背景2.算法原理2.1算法思想 3.结果展示4.参考文献5.代码获取 1.背景 2016年&#xff0c;S Mirjalili受到自然界座头鲸社会行为启发&#xff0c;提出了鲸鱼优化算法&#xff08;Whale Optimization Algorithm, WOA&#xff09;。 2.算法原理 WOA模拟了座头鲸的社会行为…

会议室占用全透明化,内幕大揭秘!

会议室管理的现实问题 &#x1f3e2; 有限的会议室资源: 在现代办公环境中&#xff0c;会议室资源通常是有限的&#xff0c;特别是在大型企业或繁忙的办公楼内&#xff0c;会议室的预订和管理变得尤为重要。 &#x1f552; 复杂的预订流程: 常常会出现会议室预订流程繁琐、不…

2024年6月14日 十二生肖 今日运势

小运播报&#xff1a;2024年6月14日&#xff0c;星期五&#xff0c;农历五月初九 &#xff08;甲辰年庚午月己酉日&#xff09;&#xff0c;法定工作日。今天世界献血日&#xff0c;捐献新鲜血液&#xff0c;挽救更多生命&#xff0c;每位献血者都是英雄&#xff01; 红榜生肖…

【论文复现|智能算法改进】基于改进鲸鱼优化算法的移动机器人多目标点路径规划

目录 1.算法原理2.数学模型3.改进点4.结果展示5.参考文献6.代码获取 1.算法原理 SCI二区|鲸鱼优化算法&#xff08;WOA&#xff09;原理及实现【附完整Matlab代码】 2.数学模型 使用 A* 算法生成所有目标点之间的距离矩阵U: U [ d 1 − 1 d 1 − 2 d 1 − 3 ⋯ d 1 − i d…

【JVM】JVisualVM的介绍、使用和GC过程

VisualVM介绍 VisualVM 是Netbeans的profile子项目&#xff0c;已在JDK6.0 update 7 中自带&#xff0c;能够监控线程&#xff0c;内存情况&#xff0c;查看方法的CPU时间和内存中的对 象&#xff0c;已被GC的对象&#xff0c;反向查看分配的堆栈(如100个String对象分别由哪几…

C#——类和对象详情

类和对象 类 类是一种数据结构&#xff0c;它可以包含数据成员&#xff08;常量和字段&#xff09;、函数成员&#xff08;方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数&#xff09;以及嵌套类型。类类型支持继承&#xff0c;继承是一种机制&…

【第9章】“基础工作流”怎么用?(图生图/局部重绘/VAE/更多基础工作流)ComfyUI基础入门教程

🎁引言 学到这里,大家是不是会比较纠结,好像还在持续学习新的东西,未来还有多少基础的东西要学习,才能正常使用ComfyUI呢? 这其实需要转变一个心态。 AI绘画还处于一个快速迭代的过程,隔三岔五的就会有很多新技术、新模型出现,ComfyUI目前同样处于一个快速更新的阶…

Flask基础2-Jinja2模板

目录 1.介绍 2.模板传参 1.变量传参 2.表达式 3.控制语句 4.过滤器 5.自定义过滤器 6.测试器 7.块和继承 flask基础1 1.介绍 Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作 者。他的设计思想来源于Django的模…

弃用Docker Desktop:在WSL2中玩转Docker之Docker Engine 部署与WSL入门

Docker技术概论 在WSL2中玩转Docker之Docker Engine部署 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://bl…

安装操作系统1-Win10版本介绍及硬件要求

注意&#xff1a;安装系统&#xff0c;首先弄清有哪些版本及所需硬件环境。 1.Win10有哪些版本 微软将 Win10为以下7个版本&#xff1a; Windows 10 家庭版&#xff08;Home&#xff09; 面向所有普通用户&#xff0c;提供Win 10的基本功能。此版本适合个人家庭用户使用&am…

Typora 破解、激活!亲测有效!2024 最新激活方法

Typora 破解、激活&#xff01;亲测有效&#xff01;2024 最新激活方法 Typora是一款简单易用的Markdown编辑器。 Markdown是一种可以使用普通文本编辑器编写的标记语言&#xff0c;通过简单的标记语法&#xff0c;它可以使普通文本内容具有一定的格式&#xff0c;其目标是实现…

机器学习第四十三周周报 aGNN

文章目录 week43 aGNN摘要Abstract1. 题目2. Abstract3. 网络架构3.1 aGNN3.1.1 输入与输出模块3.1.2 嵌入层3.1.3编码器解码器模块&#xff1a;带有多头注意力层的GCN 3.2 可释性模型&#xff1a;SHAP 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 实验区域以及场…

深度解析ONLYOFFICE协作空间2.5版本新功能

深度解析ONLYOFFICE协作空间2.5版本新功能 上个月&#xff0c;4月份&#xff0c;ONLYOFFICE协作空间推出了V2.5版本&#xff0c;丰富了一些很实用的新功能&#xff0c;之前已经有文章介绍过了&#xff1a; ONLYOFFICE 协作空间 2.5 现已发布https://blog.csdn.net/m0_6827469…

没有特斯拉的开源专利,就没有中国电动车产业今天的成就?

原文链接&#xff1a;没有特斯拉的开源专利&#xff0c;就没有中国电动车产业今天的成就&#xff1f; 特斯拉的开源专利&#xff0c;对中国电动车产业的影响有多大&#xff1f; 2014年6月12日&#xff08;June 12, 2014&#xff09;&#xff0c;特斯拉&#xff08;TESLA&…

OpenAPI Typescript Codegen 的基本使用

下载 axios npm install axios OpenAPI Typescript Codegen 官网&#xff1a;https://github.com/ferdikoomen/openapi-typescript-codegen 安装 OpenAPI Typescript Codegen npm install openapi-typescript-codegen --save-dev–input&#xff1a;指定接口文档的路径、url …