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

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

相关文章

Python在二进制文件中进行数据搜索的实战指南

《Python在二进制文件中进行数据搜索的实战指南》在二进制文件中搜索特定数据是编程中常见的任务,尤其在日志分析、程序调试和二进制数据处理中尤为重要,下面我们就来看看如何使用Python实现这一功能吧... 目录简介1. 二进制文件搜索概述2. python二进制模式文件读取(rb)2.1 二进制模式与文本

Django调用外部Python程序的完整项目实战

《Django调用外部Python程序的完整项目实战》Django是一个强大的PythonWeb框架,它的设计理念简洁优雅,:本文主要介绍Django调用外部Python程序的完整项目实战,文中通... 目录一、为什么 Django 需要调用外部 python 程序二、三种常见的调用方式方式 1:直接 im

SpringBoot整合 Quartz实现定时推送实战指南

《SpringBoot整合Quartz实现定时推送实战指南》文章介绍了SpringBoot中使用Quartz动态定时任务和任务持久化实现多条不确定结束时间并提前N分钟推送的方案,本文结合实例代码给大... 目录前言一、Quartz 是什么?1、核心定位:解决什么问题?2、Quartz 核心组件二、使用步骤1

VSCode开发中有哪些好用的插件和快捷键

《VSCode开发中有哪些好用的插件和快捷键》作为全球最受欢迎的编程工具,VSCode的快捷键体系是提升开发效率的核心密码,:本文主要介绍VSCode开发中有哪些好用的插件和快捷键的相关资料,文中... 目录前言1、vscode插件1.1 Live-server1.2 Auto Rename Tag1.3

SpringBoot整合AOP及使用案例实战

《SpringBoot整合AOP及使用案例实战》本文详细介绍了SpringAOP中的切入点表达式,重点讲解了execution表达式的语法和用法,通过案例实战,展示了AOP的基本使用、结合自定义注解以... 目录一、 引入依赖二、切入点表达式详解三、案例实战1. AOP基本使用2. AOP结合自定义注解3.

在C#中分离饼图的某个区域的操作指南

《在C#中分离饼图的某个区域的操作指南》在处理Excel饼图时,我们可能需要将饼图的各个部分分离出来,以使它们更加醒目,Spire.XLS提供了Series.DataFormat.Percent属性,... 目录引言如何设置饼图各分片之间分离宽度的代码示例:从整个饼图中分离单个分片的代码示例:引言在处理

Python列表的创建与删除的操作指南

《Python列表的创建与删除的操作指南》列表(list)是Python中最常用、最灵活的内置数据结构之一,它支持动态扩容、混合类型、嵌套结构,几乎无处不在,但你真的会创建和删除列表吗,本文给大家介绍... 目录一、前言二、列表的创建方式1. 字面量语法(最常用)2. 使用list()构造器3. 列表推导式

Agent开发核心技术解析以及现代Agent架构设计

《Agent开发核心技术解析以及现代Agent架构设计》在人工智能领域,Agent并非一个全新的概念,但在大模型时代,它被赋予了全新的生命力,简单来说,Agent是一个能够自主感知环境、理解任务、制定... 目录一、回归本源:到底什么是Agent?二、核心链路拆解:Agent的"大脑"与"四肢"1. 规划模

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处