【鸿蒙实战开发】HarmonyOS网络层的艺术——优雅封装与搭建指南-CSDN博客 (2024)

前言

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

一、网络请求的深度优化

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

在网络请求的世界里,数据格式的转换至关重要。我们通过定义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 = 100002 static 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 Error static 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 Error static 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.string.invalid_url_not_exist')); break; case NetworkServiceErrorConst.PARAMETER_ERROR: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.parameter_error')); break; case NetworkServiceErrorConst.PERMISSION_DENIED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.permission_denied')); break; case NetworkServiceErrorConst.UNSUPPORTED_PROTOCOL: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.unsupported_protocol')); break; case NetworkServiceErrorConst.BAD_URL_FORMAT: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.bad_url_format')); break; case NetworkServiceErrorConst.COULD_NOT_RESOLVE_PROXY_NAME: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.could_not_resolve_proxy_name')); break; case NetworkServiceErrorConst.COULD_NOT_RESOLVE_HOST_NAME: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.could_not_resolve_host_name')); break; case NetworkServiceErrorConst.COULD_NOT_CONNECT_TO_SERVER: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.could_not_connect_to_server')); break; case NetworkServiceErrorConst.WEIRD_SERVER_REPLY: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.weird_server_reply')); break; case NetworkServiceErrorConst.ACCESS_DENIED_TO_REMOTE_RESOURCE: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.access_denied_to_remote_resource')); break; case NetworkServiceErrorConst.HTTP2_FRAMING_LAYER_ERROR: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.http2_framing_layer_error')); break; case NetworkServiceErrorConst.TRANSFERRED_PARTIAL_FILE: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.transferred_partial_file')); break; case NetworkServiceErrorConst.FAILED_WRITING_DATA_TO_DISK: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.failed_writing_data_to_disk')); break; case NetworkServiceErrorConst.UPLOAD_FAILED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.upload_failed')); break; case NetworkServiceErrorConst.FAILED_TO_OPEN_READ_LOCAL_DATA: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.failed_to_open_read_local_data')); break; case NetworkServiceErrorConst.OUT_OF_MEMORY: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.out_of_memory')); break; case NetworkServiceErrorConst.TIMEOUT_REACHED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.timeout_reached')); break; case NetworkServiceErrorConst.REDIRECTS_EXCEEDED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.redirects_exceeded')); break; case NetworkServiceErrorConst.SERVER_RETURNED_NOTHING: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.server_returned_nothing')); break; case NetworkServiceErrorConst.FAILED_SENDING_DATA_TO_PEER: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.failed_sending_data_to_peer')); break; case NetworkServiceErrorConst.FAILURE_RECEIVING_DATA_FROM_PEER: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.failure_receiving_data_from_peer')); break; case NetworkServiceErrorConst.SSL_CERTIFICATE_PROBLEM: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.ssl_certificate_problem')); break; case NetworkServiceErrorConst.UNSUPPORTED_SSL_CIPHER: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.unsupported_ssl_cipher')); break; case NetworkServiceErrorConst.SSL_PEER_CERTIFICATE_OR_SSH_REMOTE_KEY_NOT_OK: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.ssl_peer_certificate_or_ssh_remote_key_not_ok')); break; case NetworkServiceErrorConst.UNRECOGNIZED_HTTP_CONTENT_OR_TRANSFER_ENCODING: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.unrecognized_http_content_or_transfer_encoding')); break; case NetworkServiceErrorConst.MAXIMUM_FILE_SIZE_EXCEEDED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.maximum_file_size_exceeded')); break; case NetworkServiceErrorConst.DISK_FULL_OR_ALLOCATION_EXCEEDED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.disk_full_or_allocation_exceeded')); break; case NetworkServiceErrorConst.REMOTE_FILE_ALREADY_EXISTS: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.remote_file_already_exists')); break; case NetworkServiceErrorConst.SSL_CA_CERT_PROBLEM: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.ssl_ca_cert_problem')); break; case NetworkServiceErrorConst.REMOTE_FILE_NOT_FOUND: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.remote_file_not_found')); break; case NetworkServiceErrorConst.AUTHENTICATION_FUNCTION_ERROR: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.authentication_function_error')); break; case NetworkServiceErrorConst.UNKNOWN_OTHER_ERROR: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.unknown_other_error')); break; case NetworkServiceErrorConst.BAD_REQUEST: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.bad_request')); break; case NetworkServiceErrorConst.UNAUTHORIZED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.unauthorized')); break; case NetworkServiceErrorConst.FORBIDDEN: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.forbidden')); break; case NetworkServiceErrorConst.NOT_FOUND: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.not_found')); break; case NetworkServiceErrorConst.METHOD_NOT_ALLOWED: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.method_not_allowed')); break; case NetworkServiceErrorConst.REQUEST_TIMEOUT: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.request_timeout')); break; case NetworkServiceErrorConst.UNSUPPORTED_MEDIA_TYPE: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.unsupported_media_type')); break; case NetworkServiceErrorConst.INTERNAL_SERVER_ERROR: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.internal_server_error')); break; case NetworkServiceErrorConst.BAD_GATEWAY: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.bad_gateway')); break; case NetworkServiceErrorConst.SERVICE_UNAVAILABLE: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.service_unavailable')); break; case NetworkServiceErrorConst.GATEWAY_TIMEOUT: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.gateway_timeout')); break; default: reason = Application.getInstance().resourceManager.getStringSync($r('app.string.unknown_other_error')); break; } return reason; }}

三、异常定义:清晰的错误处理策略

我们重新封装了网络请求错误,定义了BaseError和NetworkError等类,使得错误类型一目了然,便于开发者快速定位问题。

// 自定义错误类型import { http } from '@kit.NetworkKit';export abstract class BaseError extends Error{}//基本网络错误export class NetworkError extends BaseError { code : number constructor(code: number,message: string) { super(message); this.name = 'NetworkError' this.code = code }}//网络请求code错误export class NetworkResponseError extends BaseError { code : http.ResponseCode | number; constructor(code: http.ResponseCode | number,message: string) { super(message); this.name = 'NetworkResponseError' this.code = code }}

四、拦截器:网络请求的守卫

通过优化拦截器接口,我们能够在请求发送前后以及发生错误时,执行特定的逻辑,如日志记录、权限验证等。

export interface NetworkInterceptor { beforeRequest(request: RequestOptions, httprequest: http.HttpRequest): Promise<void> | void; afterResponse(response: http.HttpResponse , request: RequestOptions, httprequest: http.HttpRequest): Promise<void> | void; onError(error: BaseError, request: RequestOptions, httprequest: http.HttpRequest): Promise<void> | void;}

拦截器默认实现:

import { NetworkInterceptor } from './NetworkInterceptor';import { NetworkServiceErrorConst } from '../NetworkServiceErrorConst';import { RequestOptions } from '../NetworkService';import http from '@ohos.net.http';import { LibLogManager } from '../../LibLog';import { BaseError } from '../../../exception/NetworkError';import { JSONUtil } from '../../JSONUtil';const TAG = "DefaultInterceptor"// 创建一个符合RequestOptions接口的对象const requestOptions: RequestOptions = { baseUrl: 'https://api.example.com', act: 'someAction'};export class DefaultInterceptor implements NetworkInterceptor { beforeRequest(request: RequestOptions, httprequest: http.HttpRequest): void | Promise<void> { LibLogManager.getLogger().info(TAG,'request: ' + JSONUtil.beanToJsonStr(request)); httprequest.on('headersReceive', (header) => { LibLogManager.getLogger().info(TAG,'header: ' + JSONUtil.beanToJsonStr(header)); }); } afterResponse(response: http.HttpResponse, request: RequestOptions, httprequest: http.HttpRequest): void | Promise<void> { httprequest.off('headersReceive'); LibLogManager.getLogger().info(TAG,'response: ' + JSONUtil.beanToJsonStr(response)); } onError(error: BaseError, request: RequestOptions, httprequest: http.HttpRequest): void | Promise<void> { httprequest.off('headersReceive'); LibLogManager.getLogger().error(TAG,'error: ' + JSON.stringify(error)); } }

五、核型网络层代码:网络服务的心脏

在本节中,我们将展示如何通过NetworkService类,实现一个强大而灵活的网络请求处理机制。这个类集成了数据转换、参数附加、异常处理等所有核心功能。

 { NetworkInterceptor } from './interceptor/NetworkInterceptor';import { http } from '@kit.NetworkKit';import { LibNetworkStatus } from '../network/LibNetworkStatus';import { LibLogManager } from '../LibLog';import { BaseError, NetworkError, NetworkResponseError } from '../../exception/NetworkError';import { NetworkServiceErrorConst } from './NetworkServiceErrorConst';import { Application } from '../../app/Application'import { HashMap } from '@kit.ArkTS';import { BusinessError } from '@kit.BasicServicesKit';import { DataConverter } from './converter/DataConverter';import { QueryParamAppender } from './appender/QueryParamAppender';import { CustomQueryParamAppender } from './appender/CustomQueryParamAppender';// 1、创建RequestOption.ets 配置类export interface RequestOptions { baseUrl?: string; act?: string; method?: RequestMethod; // default is GET queryParams ?: Map<string, number|string|boolean|Array<number> | Array<string> | Array<boolean> >; header?: Record<string,string> | Map<string,string> | HashMap<string,string>; extraData?: string | Object | ArrayBuffer; expectDataType?: http.HttpDataType; usingCache?: boolean; priority?: number; connectTimeout?: number; readTimeout?: number; multiFormDataList?:Array<http.MultiFormData>;}export enum RequestMethod { OPTIONS = "OPTIONS", GET = "GET", HEAD = "HEAD", POST = "POST", PUT = "PUT", DELETE = "DELETE", TRACE = "TRACE", CONNECT = "CONNECT"}export class NetworkService { baseUrl:string; constructor(baseUrl: string) { this.baseUrl = baseUrl; } private _dataConverter?: DataConverter | undefined; // 指定转换器 public set dataConverter(value: DataConverter | undefined) { this._dataConverter = value; } private _queryParamAppender: QueryParamAppender = new CustomQueryParamAppender(); // 指定查询参数附加规则 public set queryParamAppender(value: QueryParamAppender) { this._queryParamAppender = value; } private interceptors: NetworkInterceptor[] = []; addInterceptor(interceptor: NetworkInterceptor): void { this.interceptors.push(interceptor); } async request(requestOption: RequestOptions): Promise<http.HttpResponse> { let response: http.HttpResponse | null = null; let error: BaseError | null = null; // 每一个httpRequest对应一个HTTP请求任务,不可复用 let httpRequest = http.createHttp(); //开始发请求 try { //如果url是传入的,则用传入的url requestOption.baseUrl = requestOption.baseUrl?requestOption.baseUrl:this.baseUrl; // 调用拦截器的beforeRequest方法 for (const interceptor of this.interceptors) { await interceptor.beforeRequest(requestOption, httpRequest); } let url = requestOption.baseUrl + requestOption.act; if (this._queryParamAppender) { let param = this._queryParamAppender.append(requestOption.queryParams); if(param){ url = url + "?" + param } } // 使用转换器转换请求数据 if (this._dataConverter && requestOption.extraData) { requestOption.extraData = this._dataConverter.requestConvert(requestOption.extraData); } if(requestOption.baseUrl === null || requestOption.baseUrl.trim().length === 0){ throw NetworkServiceErrorConst.getNetworkError(NetworkServiceErrorConst.URL_NOT_EXIST_ERROR) } if (!LibNetworkStatus.getInstance().isNetworkAvailable()) { LibLogManager.getLogger().error("HttpCore","网络不可用") throw NetworkServiceErrorConst.getNetworkError(NetworkServiceErrorConst.UN_AVILABLE) } if (!this.isValidUrl(requestOption.baseUrl)) { LibLogManager.getLogger().error("HttpCore","url格式不合法") throw NetworkServiceErrorConst.getNetworkError(NetworkServiceErrorConst.URL_ERROR) } let defalutHeader :Record<string,string> = { 'Content-Type': 'application/json' } let expectDataType = requestOption.expectDataType||http.HttpDataType.STRING; response = await httpRequest.request(url , { method: requestOption.method, header: requestOption.header || defalutHeader, extraData: requestOption.extraData, // 当使用POST请求时此字段用于传递内容 expectDataType: expectDataType, // 可选,指定返回数据的类型 usingCache: requestOption.usingCache, // 可选,默认为true priority: requestOption.priority, // 可选,默认为1 connectTimeout: requestOption.connectTimeout, // 可选,默认为60000ms readTimeout: requestOption.readTimeout, // 可选,默认为60000ms multiFormDataList: requestOption.multiFormDataList, }) if (http.ResponseCode.OK !== response.responseCode) { throw new NetworkResponseError(response.responseCode, NetworkServiceErrorConst.getErrorReason(response.responseCode)) } // 使用转换器转换响应数据 if (response && this._dataConverter) { response.result = this._dataConverter.responseConvert(response.result, expectDataType); } // 调用拦截器的afterResponse方法 for (const interceptor of this.interceptors) { await interceptor.afterResponse(response, requestOption, httpRequest); } } catch (e) { if(e instanceof NetworkResponseError || e instanceof NetworkError){ error = e; } else { let err = e as BusinessError; error = NetworkServiceErrorConst.getNetworkError(err.code) } } // 根据是否有错误来调用拦截器的afterResponse或onError方法 if (error) { for (const interceptor of this.interceptors) { await interceptor.onError(error, requestOption, httpRequest); } httpRequest.destroy(); throw error; // 重新抛出错误以便调用者可以处理 } else{ httpRequest.destroy(); return response!; } } private isValidUrl(url: string): boolean { // 正则表达式匹配 URL const urlPattern = new RegExp( '^(https?:\/\/)?' + // protocol '((([a-z\d]([a-z\d-]*[a-z\d])*)\.)+[a-z]{2,}|' + // domain name '((\d{1,3}\.){3}\d{1,3}))' + // OR ip (v4) address '(\:\d+)?(\/[-a-z\d%_.~+]*)*' + // port and path '(\?[;&a-z\d%_.~+=-]*)?' + // query string '(\#[-a-z\d_]*)?$', // fragment locator 'i' // ignore case ); return urlPattern.test(url); }}

结语

本文深入探讨了网络层的封装与优化,从数据转换到错误处理,每一步都体现了构建高效网络服务的艺术。希望这些实践能够帮助开发者在鸿蒙开发中游刃有余,构建出更加健壮和用户友好的应用。

写在最后

有很多小伙伴不知道该从哪里开始学习鸿蒙开发技术?也不知道鸿蒙开发的知识点重点掌握的又有哪些?自学时频繁踩坑,导致浪费大量时间。结果还是一知半解。所以有一份实用的鸿蒙(HarmonyOS NEXT)全栈开发资料用来跟着学习是非常有必要的。

获取完整版高清学习资料,请点击→鸿蒙全栈开发学习资料(安全链接,请放心点击)

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了

最新鸿蒙全栈开发学习线路【鸿蒙实战开发】HarmonyOS网络层的艺术——优雅封装与搭建指南-CSDN博客 (1)

鸿蒙HarmonyOS开发教学视频

【鸿蒙实战开发】HarmonyOS网络层的艺术——优雅封装与搭建指南-CSDN博客 (2)

大厂面试真题

【鸿蒙实战开发】HarmonyOS网络层的艺术——优雅封装与搭建指南-CSDN博客 (3)

【鸿蒙实战开发】HarmonyOS网络层的艺术——优雅封装与搭建指南-CSDN博客 (4)

鸿蒙OpenHarmony源码剖析

【鸿蒙实战开发】HarmonyOS网络层的艺术——优雅封装与搭建指南-CSDN博客 (5)

这份资料能帮住各位小伙伴理清自己的学习思路,更加快捷有效的掌握鸿蒙开发的各种知识。有需要的小伙伴自行领取,,先到先得~无套路领取!!

获取这份完整版高清学习资料,请点击→鸿蒙全栈开发学习资料(安全链接,请放心点击)

【鸿蒙实战开发】HarmonyOS网络层的艺术——优雅封装与搭建指南-CSDN博客 (2024)
Top Articles
Latest Posts
Article information

Author: Clemencia Bogisich Ret

Last Updated:

Views: 6367

Rating: 5 / 5 (80 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Clemencia Bogisich Ret

Birthday: 2001-07-17

Address: Suite 794 53887 Geri Spring, West Cristentown, KY 54855

Phone: +5934435460663

Job: Central Hospitality Director

Hobby: Yoga, Electronics, Rafting, Lockpicking, Inline skating, Puzzles, scrapbook

Introduction: My name is Clemencia Bogisich Ret, I am a super, outstanding, graceful, friendly, vast, comfortable, agreeable person who loves writing and wants to share my knowledge and understanding with you.