当前位置: 首页 > news >正文

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: stringmethod?: http.RequestMethoddata?: ObjectheaderContentType?: string
}//接口请求返回数据类
class ResponseResult {code: number //状态码message: string //处理信息data: Object | null //返回数据constructor(code?: number, message?: string, data?: Object | null | undefined) {this.code = code ?? 0this.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) => {//请求头contentTypelet contentType: string = params.headerContentType || 'application/json' //默认提交数据类型为application/json//请求数据datalet 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]}`}, '')}}//从本地存储获取tokenlet 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, //不传默认GETdata,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),'接口返回数据')}}
}

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

相关文章:

  • 解决el-table表格拖拽后,只改变了数据,表头没变的问题
  • 算法训练营day24
  • 触摸芯片在物联网和人工智能上的应用
  • udp协议下的socket函数
  • 将Firefox插件导入Edge/Chrome中
  • Redis客户端界面工具QuickRedis
  • 6_1 Linux 用户管理
  • Cohere reranker 一致的排序器
  • 【论文复现|智能算法改进】基于改进鲸鱼优化算法的移动机器人多目标点路径规划
  • 1.Vue2使用ElementUI-初识及环境搭建
  • ViewModel、Lifecycles、LiveData基本使用
  • TK防关联引流系统:全球多账号运营,一“键”掌控!
  • Typora 破解、激活!亲测有效!2024 最新激活方法
  • 排序-快排算法对数组进行排序
  • 6-11 函数题:某范围中的最小值
  • CSS居中完全指南——构建CSS居中决策树
  • DataBase in Android
  • dva中组件的懒加载
  • ES6语法详解(一)
  • HTTP中GET与POST的区别 99%的错误认识
  • k8s 面向应用开发者的基础命令
  • October CMS - 快速入门 9 Images And Galleries
  • PaddlePaddle-GitHub的正确打开姿势
  • spark本地环境的搭建到运行第一个spark程序
  • Vue.js-Day01
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • 简单易用的leetcode开发测试工具(npm)
  • 解决iview多表头动态更改列元素发生的错误
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 力扣(LeetCode)357
  • 区块链共识机制优缺点对比都是什么
  • 全栈开发——Linux
  • 深度解析利用ES6进行Promise封装总结
  • 手写一个CommonJS打包工具(一)
  • 数组大概知多少
  • 一个JAVA程序员成长之路分享
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • ​学习一下,什么是预包装食品?​
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • ()、[]、{}、(())、[[]]命令替换
  • (2)Java 简介
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (三)docker:Dockerfile构建容器运行jar包
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)大型网站的系统架构
  • (转)视频码率,帧率和分辨率的联系与区别
  • (转)树状数组
  • .naturalWidth 和naturalHeight属性,
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例