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

系列文章目录

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),'接口返回数据')
        }
     }
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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

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

云渲染动画:C4D如何正确渲染导出动画?

​C4D是一款功能强大的3D建模、动画和渲染软件&#xff0c;在制作动画时&#xff0c;正确的渲染和导出流程至关重要&#xff0c;以确保动画质量和流畅性。 帧率概念 动画就是一幅幅图片连贯起来&#xff0c;30帧/秒&#xff0c;就是一秒出现30张图片一般国外都是30&#xff0c…

打破数据分析壁垒:SPSS复习必备(一)

一、数据录入与数据获取 1.变量的测量尺度 &#xff08;1&#xff09;定类尺度 顾名思义&#xff0c;是对事物的类别或属性的一种测度&#xff0c;按照事物的某种属性对其进行分类或分组。 该类变量只能计算频数和频率&#xff0c;用表示 &#xff08;2&#xff09;定序尺…

table组件,前端如何使用table组件,打印数组数据,后端传输的数据应该如何打印

一、如何使用table&#xff0c;将数组数据打印出来 后端传来的数据&#xff0c;很大概率是一个List数组&#xff0c;我们必须用一个table组件&#xff0c;来打印这些数据。 table标签的介绍 在HTML中&#xff0c;table是常用组件之一&#xff0c;主要用来打印数组信息。 它的…

yolo-inference多后端+多任务+多算法+多精度模型 框架开发记录(python版)

先贴出github地址&#xff0c;欢迎大家批评指正&#xff1a;https://github.com/taifyang/yolo-inference 不知不觉LZ已经快工作两年了&#xff0c;由于之前的工作内容主要和模型部署相关&#xff0c;想着利用闲暇时间写一些推理方面的经验总结&#xff0c;于是有了这个工程。其…

【Pytorch】一文向您详细介绍 torch.nn.DataParallel() 的作用和用法

【Pytorch】一文向您详细介绍 torch.nn.DataParallel() 的作用和用法 下滑查看解决方法 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高…

postman 工具下载安装使用教程_postman安装

本文讲解的是postman工具下载、Postman安装步骤、postman下载、postman安装教程。Postman是一款流行的API测试工具&#xff0c;它提供了一个用户友好的界面&#xff0c;用于发送和测试API请求&#xff0c;并且可以轻松地按需管理和组织请求。 这使得开发人员和测试人员能够更高…

深圳尚水智能IPO迷局:创始人不看好公司发展退出,比亚迪加入

近日&#xff0c;上海证券交易所披露的信息显示&#xff0c;深圳市尚水智能股份有限公司&#xff08;下称“尚水智能”&#xff09;及其保荐人民生证券撤回上市申请文件。因此&#xff0c;上海证券交易所决定终止对其首次公开发行股票并在科创板上市的审核。 据贝多财经了解&am…

【ARMv8/ARMv9 硬件加速系列 1 -- SVE | NEON | SIMD | VFP | MVE | MPE 基础介绍】

文章目录 ARM 扩展功能介绍VFP (Vector Floating Point)SIMD (Single Instruction, Multiple Data)NEONSVE (Scalable Vector Extension)SME (Scalable Matrix Extension)CME (Compute Matrix Engine)MVE (M-profile Vector Extension)MPE (Media Processing Engine)总结 ARM 扩…

App推广效果分析,Xinstall助力精准优化

App推广效果分析&#xff1a;Xinstall助力精准优化 在App推广的激烈竞争中&#xff0c;如何确保每一次推广活动都能带来最佳效果&#xff0c;是每个运营者都关心的问题。Xinstall作为一款专业的App推广工具&#xff0c;不仅提供了全方位的推广支持&#xff0c;还能通过精准的数…

Maven 快速入门

Maven 简介 Maven是apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 依赖管理 方便快捷的管理项目的依赖资源(jar包),避免版本冲突 配置 依赖: 指当前项目运行所需要的(jar包) 在pom.xml 中编写<dependencies> 标签 在<dependencies…

选择制造业生产管理系统指南

在当今日益激烈的市场竞争中&#xff0c;制造业企业要想保持领先地位&#xff0c;就必须拥有一套高效、智能的生产管理系统。选择一套合适的制造业生产管理系统&#xff0c;不仅能帮助企业优化生产流程、提高生产效率&#xff0c;还能降低生产成本、提升产品质量。 一、发现制…

2024/06/13--代码随想录算法3/17|01背包问题 二维、01背包问题 一维、416. 分割等和子集

01背包问题 二维 卡码网链接 动态规划5步曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义&#xff1a;dp[i][j] &#xff1a;从下标为[0,i-1]个物品中任取&#xff0c;放进容量为j的背包&#xff0c;价值总和最大为多少。确定递推公式&#xff0c; 有两个方向可…

简单操作,智能自动化:Windows键鼠模拟软件

一个 Windows 自动化工具&#xff0c;可模拟键盘和鼠标&#xff0c;自动执行任何流程和动作&#xff0c;只需录制动作并运行即可&#xff0c;无需编写脚本&#xff0c;只需按录制&#xff0c;然后播放即可&#xff0c;大小仅 35 KB&#xff0c;且免费无广告。 界面介绍 **打开…

pyside6在QLabel上显示图像文件

猫咪的图片&#xff1a;370*280像素 基本的代码&#xff1a; from PySide6.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout from PySide6.QtGui import QPixmap, Qtapp QApplication([])widget QWidget() layout QVBoxLayout(widget)label QLabel() label.…

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

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

计算机网络 —— 运输层(TCP三次握手)

计算机网络 —— 运输层&#xff08;TCP三次握手&#xff09; 三次握手第一次握手第二次握手第三次握手两次握手行不行&#xff1f; 我们今天来学习TCP的三次握手&#xff1a; 三次握手 TCP三次握手是TCP协议中建立连接的过程&#xff0c;旨在确保双方准备好进行可靠的通信。…

JavaScript之函数

函数 使用 声明语法&#xff1a; function 函数名() {函数体 }命名规范&#xff1a; 小驼峰命名法前缀用动词 前缀词&#xff1a; 调用 函数名()函数传参 为了提高函数的灵活性 声明语法&#xff1a; function 函数名(参数列表) {函数体 }调用 函数名(参数)在函数声…

登录/注册- 滑动拼图验证码(IOS/Swift)

本章介绍如何使用ios开发出滑动拼图验证码&#xff0c;分别OC代码和swift代码调用 1.导入项目model文件OC代码&#xff08;下载完整Demo&#xff09; 2.放入你需要显示的图片 一&#xff1a;OC调用 #import "ViewController.h" #import "CodeView.h"…

强大高效,推荐这两款分析文章和抠图的AI工具

ChatDOC ChatDOC是一款基于ChatGPT的AI阅读辅助工具&#xff0c;旨在通过与用户指定的文档进行对话来处理用户的专属数据。它能够帮助用户快速提取文档中的信息&#xff0c;支持多种文件格式&#xff0c;并提供准确的答案。此外&#xff0c;ChatDOC还具备智能格式化、自动摘要生…