鸿蒙实战开发:网络层的艺术——优雅封装与搭建指南(中)

2024-06-17 22:36

本文主要是介绍鸿蒙实战开发:网络层的艺术——优雅封装与搭建指南(中),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

在鸿蒙开发的广袤天地中,网络层的搭建与封装无疑是构建高效、稳定应用的基石。继上篇的探索之后,本文将继续深入网络层的优化之旅,揭秘如何通过类型转换器、请求查询附加器以及丰富的常量参数,将网络层的构建艺术推向一个新的高度。

一、网络请求的深度优化

数据类型转换器:定义与实践

在网络请求的世界里,数据格式的转换至关重要。我们通过定义DataConverter接口,实现了对请求与响应数据类型的灵活转换。

export interface DataConverter {requestConvert(extraData: string | Object | ArrayBuffer): string | Object | ArrayBuffer;responseConvert(data: string | Object | ArrayBuffer, responseType: http.HttpDataType): string | Object | ArrayBuffer;
}
默认数据转换器:JSON转换器的实现

我们实现了一个默认的JsonDataConverter,它将请求数据转换为JSON字符串,并根据响应类型将响应数据转换为适当的格式。


export class JsonDataConverter implements DataConverter {requestConvert(extraData: string | Object | ArrayBuffer): string | Object | ArrayBuffer {// 将请求数据转换为JSON字符串return JSONUtil.beanToJsonStr(extraData);}responseConvert(data: string | Object | ArrayBuffer, responseType: http.HttpDataType): string | Object | ArrayBuffer {// 根据responseType将响应数据转换为相应的格式switch (responseType) {case http.HttpDataType.STRING:return JSON.parse(data as string);case http.HttpDataType.OBJECT:return data;default:return data;}}
}

参数附加器:灵活重组请求数据

参数附加器QueryParamAppender接口允许我们对发送的请求数据进行重组,满足诸如参数签名等业务需求。

// 定义一个用于附加查询参数的接口
export interface QueryParamAppender {append(queryParams?: Map<string, number|string|boolean|Array<number> | Array<string> | Array<boolean> >): string|undefined;
}
默认附加器:简化查询参数的处理

通过CustomQueryParamAppender的实现,我们简化了查询参数的编码和附加过程。


export class CustomQueryParamAppender implements QueryParamAppender {append(queryParams?: Map<string, string | number | boolean | number[] | string[] | boolean[]> | undefined): string|undefined {if (queryParams===undefined || queryParams.size === 0) {return;}const paramsArray: string[] = [];for (const qp of queryParams) {let key = qp[0]let value = qp[1]let encodedValue = '';if (Array.isArray(value)) {for (let i = 0; i < value.length; i++) {encodedValue += `${encodeURIComponent(`${key}[${i}]`)}=${encodeURIComponent(value[i].toString())}&`;}if (encodedValue.length > 0) {encodedValue = encodedValue.slice(0, -1); // 移除最后一个 '&'}} else {encodedValue = encodeURIComponent(key) + '=' + encodeURIComponent(value.toString());}paramsArray.push(encodedValue);}return paramsArray.join('&');}}

二、常量定义:构建网络层的坚实基础

通过定义一系列的常量,我们为网络请求的错误处理提供了统一的接口。这些常量不仅包括了各种网络错误的场景,还涵盖了HTTP状态码的含义,为开发者提供了清晰的指导。

{"name": "network_unavailable","value": "网络不可用"},{"name": "invalid_url_format","value": "URL格式不合法"},{"name": "invalid_url_not_exist","value": "URL不存在"},{"name": "parameter_error","value": "参数错误"},{"name": "permission_denied","value": "权限被拒绝"},{"name": "unsupported_protocol","value": "不支持的协议"},{"name": "bad_url_format","value": "URL使用错误的/非法的格式或缺少URL"},{"name": "could_not_resolve_proxy_name","value": "无法解析代理名称"},{"name": "could_not_resolve_host_name","value": "无法解析主机名"},{"name": "could_not_connect_to_server","value": "无法连接到服务器"},{"name": "weird_server_reply","value": "服务器回复异常"},{"name": "access_denied_to_remote_resource","value": "访问远程资源被拒绝"},{"name": "http2_framing_layer_error","value": "HTTP2帧层错误"},{"name": "transferred_partial_file","value": "传输了部分文件"},{"name": "failed_writing_data_to_disk","value": "将数据写入磁盘/应用程序失败"},{"name": "upload_failed","value": "上传失败"},{"name": "failed_to_open_read_local_data","value": "无法打开/读取本地数据"},{"name": "out_of_memory","value": "内存不足"},{"name": "timeout_reached","value": "达到超时时间"},{"name": "redirects_exceeded","value": "达到重定向的最大次数"},{"name": "server_returned_nothing","value": "服务器未返回任何内容(无头信息,无数据)"},{"name": "failed_sending_data_to_peer","value": "向对等端发送数据失败"},{"name": "failure_receiving_data_from_peer","value": "从对等端接收数据失败"},{"name": "ssl_certificate_problem","value": "本地SSL证书问题"},{"name": "unsupported_ssl_cipher","value": "不支持指定的SSL加密算法"},{"name": "ssl_peer_certificate_or_ssh_remote_key_not_ok","value": "SSL对等证书或SSH远程密钥不正确"},{"name": "unrecognized_http_content_or_transfer_encoding","value": "无法识别的HTTP内容或传输编码"},{"name": "maximum_file_size_exceeded","value": "超过最大文件大小"},{"name": "disk_full_or_allocation_exceeded","value": "磁盘已满或分配超过限制"},{"name": "remote_file_already_exists","value": "远程文件已存在"},{"name": "ssl_ca_cert_problem","value": "SSL CA证书问题(路径?访问权限?)"},{"name": "remote_file_not_found","value": "远程文件未找到"},{"name": "authentication_function_error","value": "身份验证函数返回错误"},{"name": "unknown_other_error","value": "未知的其他错误"},{"name": "bad_request","value": "客户端请求的语法错误,服务器无法理解。"},{"name": "unauthorized","value": "请求要求身份验证。"},{"name": "forbidden","value": "服务器理解请求客户端的请求,但是拒绝执行此请求。"},{"name": "not_found","value": "服务器无法根据客户端的请求找到资源(网页)。"},{"name": "method_not_allowed","value": "客户端请求中的方法被禁止。"},{"name": "request_timeout","value": "请求超时。"},{"name": "unsupported_media_type","value": "服务器不支持请求的格式(如请求中包含了服务器不支持的MIME类型)。"},{"name": "internal_server_error","value": "服务器内部错误,无法完成请求。"},{"name": "bad_gateway","value": "作为网关或代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。"},{"name": "service_unavailable","value": "由于超载或系统维护,服务器目前无法处理请求。"},{"name": "gateway_timeout","value": "作为网关或代理工作的服务器尝试执行请求时,未能及时从上游服务器收到需要的响应。"}

常量类代码使用

import { Application } from '../../app/Application'
import { NetworkError } from '../../exception/NetworkError'export class NetworkServiceErrorConst {// 网络不可用static readonly UN_AVILABLE: number = 100000// url错误static readonly URL_ERROR: number = 100001// url 不存在 错误static readonly URL_NOT_EXIST_ERROR: number = 100002static readonly PARAMETER_ERROR: number = 401;static readonly PERMISSION_DENIED: number = 201;static readonly UNSUPPORTED_PROTOCOL: number = 2300001;static readonly BAD_URL_FORMAT: number = 2300003;static readonly COULD_NOT_RESOLVE_PROXY_NAME: number = 2300005;static readonly COULD_NOT_RESOLVE_HOST_NAME: number = 2300006;static readonly COULD_NOT_CONNECT_TO_SERVER: number = 2300007;static readonly WEIRD_SERVER_REPLY: number = 2300008;static readonly ACCESS_DENIED_TO_REMOTE_RESOURCE: number = 2300009;static readonly HTTP2_FRAMING_LAYER_ERROR: number = 2300016;static readonly TRANSFERRED_PARTIAL_FILE: number = 2300018;static readonly FAILED_WRITING_DATA_TO_DISK: number = 2300023;static readonly UPLOAD_FAILED: number = 2300025;static readonly FAILED_TO_OPEN_READ_LOCAL_DATA: number = 2300026;static readonly OUT_OF_MEMORY: number = 2300027;static readonly TIMEOUT_REACHED: number = 2300028;static readonly REDIRECTS_EXCEEDED: number = 2300047;static readonly SERVER_RETURNED_NOTHING: number = 2300052;static readonly FAILED_SENDING_DATA_TO_PEER: number = 2300055;static readonly FAILURE_RECEIVING_DATA_FROM_PEER: number = 2300056;static readonly SSL_CERTIFICATE_PROBLEM: number = 2300058;static readonly UNSUPPORTED_SSL_CIPHER: number = 2300059;static readonly SSL_PEER_CERTIFICATE_OR_SSH_REMOTE_KEY_NOT_OK: number = 2300060;static readonly UNRECOGNIZED_HTTP_CONTENT_OR_TRANSFER_ENCODING: number = 2300061;static readonly MAXIMUM_FILE_SIZE_EXCEEDED: number = 2300063;static readonly DISK_FULL_OR_ALLOCATION_EXCEEDED: number = 2300070;static readonly REMOTE_FILE_ALREADY_EXISTS: number = 2300073;static readonly SSL_CA_CERT_PROBLEM: number = 2300077;static readonly REMOTE_FILE_NOT_FOUND: number = 2300078;static readonly AUTHENTICATION_FUNCTION_ERROR: number = 2300094;static readonly UNKNOWN_OTHER_ERROR: number = 2300999;// 4xx Client Errorstatic readonly BAD_REQUEST: number = 400;static readonly UNAUTHORIZED: number = 401;static readonly FORBIDDEN: number = 403;static readonly NOT_FOUND: number = 404;static readonly METHOD_NOT_ALLOWED: number = 405;static readonly REQUEST_TIMEOUT: number = 408;static readonly UNSUPPORTED_MEDIA_TYPE: number = 415;// 5xx Server Errorstatic readonly INTERNAL_SERVER_ERROR: number = 500;static readonly BAD_GATEWAY: number = 502;static readonly SERVICE_UNAVAILABLE: number = 503;static readonly GATEWAY_TIMEOUT: number = 504;public static getNetworkError(code: number): NetworkError{return new NetworkError(code, NetworkServiceErrorConst.getErrorReason(code));}public static getErrorReason(errorCode: number): string {let reason = "";switch (errorCode) {case NetworkServiceErrorConst.UN_AVILABLE:reason = Application.getInstance().resourceManager.getStringSync($r('app.string.network_unavailable'));break;case NetworkServiceErrorConst.URL_ERROR:reason = Application.getInstance().resourceManager.getStringSync($r('app.string.invalid_url_format'));break;case NetworkServiceErrorConst.URL_NOT_EXIST_ERROR:reason = Application.getInstance().resourceManager.getStringSync($r('app.st

这篇关于鸿蒙实战开发:网络层的艺术——优雅封装与搭建指南(中)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1070623

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

搭建Kafka+zookeeper集群调度

前言 硬件环境 172.18.0.5        kafkazk1        Kafka+zookeeper                Kafka Broker集群 172.18.0.6        kafkazk2        Kafka+zookeeper                Kafka Broker集群 172.18.0.7        kafkazk3