HarmonyOS鸿蒙Next开发者技术支持网络请求对象快速序列化方案

HarmonyOS鸿蒙Next开发者技术支持网络请求对象快速序列化方案

什么是对象序列化?

对象序列化是指将内存中的对象转换为可以存储或传输的格式(如JSON、Protocol Buffers等),以及从这些格式重新构建对象的过程。在网络请求中,序列化是数据交换的核心环节。

环境准备和基础配置

步骤1:配置模块依赖和权限

// module.json5 配置
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ],
    "dependencies": [
      {
        "bundleName": "com.example.serialization",
        "moduleName": "serialization",
        "versionCode": 1000000
      }
    ]
  }
}

首先配置网络权限和必要的依赖模块,确保应用具备网络访问能力和序列化功能的基础支持。

核心序列化API详解

步骤2:使用ArkTS内置序列化能力

// 基础序列化工具类
import { util } from '@kit.ArkTS';

export class BaseSerializer {
  
  // 对象转JSON字符串 - 使用ArkTS内置的util工具
  static objectToJson<T>(obj: T): string {
    try {
      return JSON.stringify(obj, (key, value) => {
        // 处理特殊类型:Date、undefined等
        if (value instanceof Date) {
          return value.toISOString();
        }
        if (value === undefined) {
          return null;
        }
        return value;
      });
    } catch (error) {
      console.error('对象转JSON失败:', JSON.stringify(error));
      return '{}';
    }
  }
  
  // JSON字符串转对象 - 支持类型安全转换
  static jsonToObject<T>(jsonString: string, constructor?: new () => T): T {
    try {
      const rawObject = JSON.parse(jsonString);
      
      if (constructor) {
        // 如果有构造函数,创建类型实例并复制属性
        return this.createTypedInstance(rawObject, constructor);
      }
      
      return rawObject as T;
    } catch (error) {
      console.error('JSON转对象失败:', JSON.stringify(error));
      return {} as T;
    }
  }
  
  // 创建类型化实例
  private static createTypedInstance<T>(data: any, constructor: new () => T): T {
    const instance = new constructor();
    Object.keys(data).forEach(key => {
      if (key in instance) {
        (instance as any)[key] = data[key];
      }
    });
    return instance;
  }
}

利用ArkTS内置的JSON序列化能力,处理基本的数据类型转换,同时提供类型安全的对象重建功能。

网络请求数据模型定义

步骤3:定义可序列化的数据模型基类

// 可序列化接口定义
export interface Serializable {
  toJson(): string;
  fromJson(json: string): void;
}

// 基础响应模型
export class BaseResponse implements Serializable {
  code: number = 0;
  message: string = '';
  timestamp: number = 0;
  
  constructor(code?: number, message?: string) {
    if (code) this.code = code;
    if (message) this.message = message;
    this.timestamp = new Date().getTime();
  }
  
  // 序列化为JSON
  toJson(): string {
    return BaseSerializer.objectToJson(this);
  }
  
  // 从JSON反序列化
  fromJson(json: string): void {
    const data = BaseSerializer.jsonToObject<BaseResponse>(json);
    Object.assign(this, data);
  }
  
  // 快速检查请求是否成功
  isSuccess(): boolean {
    return this.code === 0 || this.code === 200;
  }
}

定义统一的序列化接口和基础响应模型,确保所有网络数据模型都具备序列化能力。

步骤4:创建具体的业务数据模型

// 用户数据模型
export class UserModel extends BaseResponse {
  userId: string = '';
  username: string = '';
  email: string = '';
  avatar: string = '';
  createTime: Date = new Date();
  
  // 自定义序列化逻辑 - 处理Date类型
  toJson(): string {
    const serializableData = {
      ...this,
      createTime: this.createTime.toISOString()
    };
    return BaseSerializer.objectToJson(serializableData);
  }
  
  // 自定义反序列化逻辑
  fromJson(json: string): void {
    const data = BaseSerializer.jsonToObject<any>(json);
    this.userId = data.userId || '';
    this.username = data.username || '';
    this.email = data.email || '';
    this.avatar = data.avatar || '';
    this.createTime = data.createTime ? new Date(data.createTime) : new Date();
    this.code = data.code || 0;
    this.message = data.message || '';
  }
  
  // 快速创建实例的静态方法
  static createFromNetwork(data: any): UserModel {
    const user = new UserModel();
    user.fromJson(BaseSerializer.objectToJson(data));
    return user;
  }
}

// 列表响应模型
export class ListResponse<T> extends BaseResponse {
  data: T[] = [];
  total: number = 0;
  page: number = 1;
  pageSize: number = 20;
  
  constructor(data?: T[]) {
    super();
    if (data) this.data = data;
  }
  
  fromJson(json: string): void {
    const parsed = BaseSerializer.jsonToObject<ListResponse<T>>(json);
    this.data = parsed.data || [];
    this.total = parsed.total || 0;
    this.page = parsed.page || 1;
    this.pageSize = parsed.pageSize || 20;
    this.code = parsed.code || 0;
    this.message = parsed.message || '';
  }
}

通过继承基类实现具体业务模型,处理特殊数据类型(如Date),并提供便捷的创建方法。

网络请求封装与序列化集成

步骤5:封装支持自动序列化的HTTP客户端

import { http } from '@kit.ArkTS';
import { BusinessError } from '@kit.BasicServicesKit';

export class SerializationHttpClient {
  private baseUrl: string = '';
  private timeout: number = 30000;
  
  constructor(baseUrl: string, timeout?: number) {
    this.baseUrl = baseUrl;
    if (timeout) this.timeout = timeout;
  }
  
  // 通用请求方法
  async request<T extends BaseResponse>(
    config: http.HttpRequestOptions,
    responseType: new () => T
  ): Promise<T> {
    try {
      // 创建HTTP请求
      const httpRequest = http.createHttp();
      const fullUrl = `${this.baseUrl}${config.url}`;
      
      // 设置请求配置
      const requestConfig: http.HttpRequestOptions = {
        ...config,
        url: fullUrl,
        readTimeout: this.timeout,
        connectTimeout: this.timeout
      };
      
      // 发送请求
      const response = await httpRequest.request(requestConfig);
      
      if (response.responseCode === http.ResponseCode.OK) {
        // 获取响应数据并反序列化
        const result = await this.handleResponse<T>(response, responseType);
        return result;
      } else {
        throw new Error(`HTTP错误: ${response.responseCode}`);
      }
    } catch (error) {
      console.error('网络请求失败:', JSON.stringify(error));
      return this.createErrorResponse(responseType, error);
    }
  }
  
  // 处理响应数据
  private async handleResponse<T extends BaseResponse>(
    response: http.HttpResponse,
    responseType: new () => T
  ): Promise<T> {
    const result = new responseType();
    
    try {
      // 读取响应体
      const responseBody = await response.result;
      let responseData: string;
      
      if (typeof responseBody === 'string') {
        responseData = responseBody;
      } else {
        // 处理ArrayBuffer等类型
        responseData = String.fromCharCode.apply(null, new Uint8Array(responseBody as ArrayBuffer));
      }
      
      console.info('原始响应数据:', responseData);
      
      // 反序列化为目标类型
      result.fromJson(responseData);
      return result;
      
    } catch (parseError) {
      console.error('响应数据解析失败:', JSON.stringify(parseError));
      result.code = -1;
      result.message = '数据解析失败';
      return result;
    }
  }
  
  // 创建错误响应
  private createErrorResponse<T extends BaseResponse>(
    responseType: new () => T,
    error: BusinessError
  ): T {
    const result = new responseType();
    result.code = -1;
    result.message = error.message || '网络请求失败';
    return result;
  }
}

封装HTTP客户端,集成自动序列化功能,将网络响应自动转换为类型化的对象实例。

步骤6:实现具体的API服务类

// 用户API服务
export class UserApiService {
  private httpClient: SerializationHttpClient;
  
  constructor(baseUrl: string) {
    this.httpClient = new SerializationHttpClient(baseUrl);
  }
  
  // 获取用户信息
  async getUserInfo(userId: string): Promise<UserModel> {
    const config: http.HttpRequestOptions = {
      method: http.RequestMethod.GET,
      url: `/api/users/${userId}`,
      header: {
        'Content-Type': 'application/json'
      }
    };
    
    return await this.httpClient.request(config, UserModel);
  }
  
  // 更新用户信息
  async updateUserInfo(user: UserModel): Promise<BaseResponse> {
    const config: http.HttpRequestOptions = {
      method: http.RequestMethod.PUT,
      url: '/api/users/update',
      header: {
        'Content-Type': 'application/json'
      },
      extraData: user.toJson() // 自动序列化请求体
    };
    
    return await this.httpClient.request(config, BaseResponse);
  }
  
  // 获取用户列表(支持泛型)
  async getUserList(page: number = 1, pageSize: number = 20): Promise<ListResponse<UserModel>> {
    const config: http.HttpRequestOptions = {
      method: http.RequestMethod.GET,
      url: `/api/users?page=${page}&pageSize=${pageSize}`,
      header: {
        'Content-Type': 'application/json'
      }
    };
    
    return await this.httpClient.request(config, ListResponse<UserModel>);
  }
}

基于封装的HTTP客户端实现具体API服务,提供类型安全的网络请求方法。

高级序列化特性

步骤7:实现注解驱动的序列化

// 序列化注解定义
export function SerializedName(name: string) {
  return function (target: any, propertyKey: string) {
    if (!target.constructor._serializedNameMap) {
      target.constructor._serializedNameMap = new Map();
    }
    target.constructor._serializedNameMap.set(propertyKey, name);
  };
}

export function IgnoreSerialization(target: any, propertyKey: string) {
  if (!target.constructor._ignoreProperties) {
    target.constructor._ignoreProperties = new Set();
  }
  target.constructor._ignoreProperties.add(propertyKey);
}

// 支持注解的序列化器
export class AnnotationSerializer {
  
  // 支持注解的序列化方法
  static objectToJsonWithAnnotations<T>(obj: T): string {
    const serializableObject: any = {};
    const prototype = Object.getPrototypeOf(obj);
    
    // 获取类注解信息
    const serializedNameMap = prototype.constructor._serializedNameMap as Map<string, string> || new Map();
    const ignoreProperties = prototype.constructor._ignoreProperties as Set<string> || new Set();
    
    Object.keys(obj as any).forEach(key => {
      // 检查是否忽略该属性
      if (ignoreProperties.has(key)) {
        return;
      }
      
      // 获取序列化后的字段名
      const serializedName = serializedNameMap.get(key) || key;
      const value = (obj as any)[key];
      
      // 处理特殊类型
      if (value instanceof Date) {
        serializableObject[serializedName] = value.toISOString();
      } else if (value !== undefined && value !== null) {
        serializableObject[serializedName] = value;
      }
    });
    
    return JSON.stringify(serializableObject);
  }
  
  // 支持注解的反序列化方法
  static jsonToObjectWithAnnotations<T>(jsonString: string, constructor: new () => T): T {
    const instance = new constructor();
    const data = JSON.parse(jsonString);
    
    const prototype = Object.getPrototypeOf(instance);
    const serializedNameMap = prototype.constructor._serializedNameMap as Map<string, string> || new Map();
    
    // 创建反向映射:序列化名 -> 属性名
    const reverseMap = new Map<string, string>();
    serializedNameMap.forEach((value, key) => {
      reverseMap.set(value, key);
    });
    
    Object.keys(data).forEach(jsonKey => {
      // 查找对应的属性名
      const propertyName = reverseMap.get(jsonKey) || jsonKey;
      
      if (propertyName in instance) {
        const value = data[jsonKey];
        
        // 特殊类型处理
        if (typeof value === 'string' && this.isIsoDateString(value)) {
          (instance as any)[propertyName] = new Date(value);
        } else {
          (instance as any)[propertyName] = value;
        }
      }
    });
    
    return instance;
  }
  
  private static isIsoDateString(value: string): boolean {
    return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value);
  }
}

通过注解方式实现更灵活的序列化控制,支持字段重命名和忽略特定属性。

步骤8:使用注解的模型示例

// 使用注解的增强用户模型
export class EnhancedUserModel extends BaseResponse {
  @SerializedName('user_id')
  userId: string = '';
  
  @SerializedName('user_name')
  username: string = '';
  
  email: string = '';
  
  @IgnoreSerialization
  temporaryToken: string = ''; // 这个字段不会被序列化
  
  @SerializedName('created_at')
  createTime: Date = new Date();
  
  toJson(): string {
    return AnnotationSerializer.objectToJsonWithAnnotations(this);
  }
  
  fromJson(json: string): void {
    const instance = AnnotationSerializer.jsonToObjectWithAnnotations(json, EnhancedUserModel);
    Object.assign(this, instance);
  }
}

性能优化和缓存策略

步骤9:实现序列化缓存

// 序列化缓存管理器
export class SerializationCacheManager {
  private static instance: SerializationCacheManager;
  private cache: Map<string, { data: any, timestamp: number }> = new Map();
  private readonly maxCacheSize: number = 1000;
  private readonly cacheTTL: number = 5 * 60 * 1000; // 5分钟
  
  static getInstance(): SerializationCacheManager {
    if (!SerializationCacheManager.instance) {
      SerializationCacheManager.instance = new SerializationCacheManager();
    }
    return SerializationCacheManager.instance;
  }
  
  // 缓存序列化结果
  setCache(key: string, data: any): void {
    if (this.cache.size >= this.maxCacheSize) {
      // 清理过期缓存
      this.cleanExpiredCache();
    }
    
    this.cache.set(key, {
      data: data,
      timestamp: Date.now()
    });
  }
  
  // 获取缓存数据
  getCache<T>(key: string): T | null {
    const cached = this.cache.get(key);
    
    if (!cached) {
      return null;
    }
    
    // 检查是否过期
    if (Date.now() - cached.timestamp > this.cacheTTL) {
      this.cache.delete(key);
      return null;
    }
    
    return cached.data as T;
  }
  
  // 清理过期缓存
  private cleanExpiredCache(): void {
    const now = Date.now();
    for (const [key, value] of this.cache.entries()) {
      if (now - value.timestamp > this.cacheTTL) {
        this.cache.delete(key);
      }
    }
  }
}

// 带缓存的序列化服务
export class CachedSerializationService {
  private cacheManager = SerializationCacheManager.getInstance();
  
  // 带缓存的序列化
  serializeWithCache<T>(obj: T, cacheKey: string): string {
    // 尝试从缓存获取
    const cached = this.cacheManager.getCache<string>(cacheKey);
    if (cached) {
      return cached;
    }
    
    // 执行序列化并缓存结果
    const result = BaseSerializer.objectToJson(obj);
    this.cacheManager.setCache(cacheKey, result);
    
    return result;
  }
  
  // 带缓存的反序列化
  deserializeWithCache<T>(jsonString: string, constructor: new () => T, cacheKey: string): T {
    const cached = this.cacheManager.getCache<T>(cacheKey);
    if (cached) {
      return cached;
    }
    
    const result = BaseSerializer.jsonToObject(jsonString, constructor);
    this.cacheManager.setCache(cacheKey, result);
    
    return result;
  }
}

完整使用示例

步骤10:在实际项目中使用

[@Entry](/user/Entry)
[@Component](/user/Component)
struct NetworkExamplePage {
  [@State](/user/State) userInfo: UserModel = new UserModel();
  [@State](/user/State) userList: ListResponse<UserModel> = new ListResponse();
  [@State](/user/State) isLoading: boolean = false;
  
  private userApi: UserApiService = new UserApiService('https://api.example.com');
  private cachedService: CachedSerializationService = new CachedSerializationService();
  
  aboutToAppear() {
    this.loadUserData();
  }
  
  async loadUserData() {
    this.isLoading = true;
    
    try {
      // 获取用户信息
      const userResult = await this.userApi.getUserInfo('12345');
      if (userResult.isSuccess()) {
        this.userInfo = userResult;
        
        // 缓存用户信息
        const cacheKey = `user_${this.userInfo.userId}`;
        this.cachedService.serializeWithCache(this.userInfo, cacheKey);
      }
      
      // 获取用户列表
      const listResult = await this.userApi.getUserList(1, 10);
      if (

更多关于HarmonyOS鸿蒙Next开发者技术支持网络请求对象快速序列化方案的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

HarmonyOS Next网络请求对象序列化推荐使用ArkTS的JSON.stringify()方法。对于复杂对象,可通过@Observed装饰器配合@Track装饰属性实现响应式序列化。序列化时注意处理循环引用,建议使用toJSON()自定义序列化逻辑。网络请求推荐使用@ohos.net.http模块,结合JSON.parse()反序列化响应数据。

更多关于HarmonyOS鸿蒙Next开发者技术支持网络请求对象快速序列化方案的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这是一个非常全面和专业的HarmonyOS Next网络请求序列化方案。你的方案覆盖了从基础到高级的完整实现路径,结构清晰,代码规范。以下是我对几个关键点的补充和优化建议:

1. 关于序列化基类的优化 你的BaseSerializer处理了Dateundefined类型,这是很好的实践。可以考虑进一步扩展对MapSet等特殊类型的支持:

static objectToJson<T>(obj: T): string {
  return JSON.stringify(obj, (key, value) => {
    if (value instanceof Date) {
      return value.toISOString();
    }
    if (value instanceof Map) {
      return Object.fromEntries(value);
    }
    if (value instanceof Set) {
      return Array.from(value);
    }
    if (value === undefined) {
      return null;
    }
    return value;
  });
}

2. 类型安全反序列化的增强 当前createTypedInstance方法通过key in instance检查属性存在性,这能防止注入不存在的属性。但可以考虑使用TypeScript的装饰器或运行时类型检查来确保类型安全:

import { Type } from '@kit.ArkTS';

// 使用反射获取类型信息
static createTypedInstance<T>(data: any, constructor: new () => T): T {
  const instance = new constructor();
  const metadata = Reflect.getMetadata('design:type', instance, key);
  
  Object.keys(data).forEach(key => {
    if (key in instance) {
      // 根据metadata进行类型转换
      const targetType = metadata[key];
      (instance as any)[key] = this.convertValue(data[key], targetType);
    }
  });
  return instance;
}

3. HTTP客户端的性能优化 你的SerializationHttpClient已经很好,但可以添加请求拦截器和响应拦截器,方便统一处理认证、日志等:

interface HttpInterceptor {
  onRequest?(config: http.HttpRequestOptions): http.HttpRequestOptions;
  onResponse?(response: http.HttpResponse): http.HttpResponse;
  onError?(error: BusinessError): void;
}

class SerializationHttpClient {
  private interceptors: HttpInterceptor[] = [];
  
  addInterceptor(interceptor: HttpInterceptor): void {
    this.interceptors.push(interceptor);
  }
  
  private async processRequest(config: http.HttpRequestOptions): Promise<http.HttpRequestOptions> {
    let processedConfig = config;
    for (const interceptor of this.interceptors) {
      if (interceptor.onRequest) {
        processedConfig = interceptor.onRequest(processedConfig);
      }
    }
    return processedConfig;
  }
}

4. 注解序列化的运行时性能 你的注解方案很优雅,但注意Object.getPrototypeOf和反射操作在频繁调用时可能有性能开销。可以考虑在类初始化时缓存注解信息:

class AnnotationSerializer {
  private static annotationCache = new Map<Function, {
    serializedNameMap: Map<string, string>;
    ignoreProperties: Set<string>;
  }>();
  
  static getAnnotations(constructor: Function) {
    if (!this.annotationCache.has(constructor)) {
      // 解析并缓存注解信息
      const annotations = this.parseAnnotations(constructor);
      this.annotationCache.set(constructor, annotations);
    }
    return this.annotationCache.get(constructor)!;
  }
}

5. 缓存策略的改进 当前缓存是基于内存的,对于大型应用可以考虑分级缓存策略:

enum CacheLevel {
  MEMORY = 'memory',
  PERSISTENT = 'persistent',
  NETWORK = 'network'
}

class MultiLevelCacheManager {
  async getWithFallback<T>(
    key: string,
    fetcher: () => Promise<T>,
    level: CacheLevel = CacheLevel.MEMORY
  ): Promise<T> {
    // 1. 检查内存缓存
    // 2. 检查持久化缓存
    // 3. 网络请求
    // 4. 更新各级缓存
  }
}

6. 错误处理的完整性 你的错误处理已经很全面,可以进一步添加重试机制和熔断器模式:

class RetryableHttpClient {
  private maxRetries = 3;
  private retryDelay = 1000;
  
  async requestWithRetry<T extends BaseResponse>(
    config: http.HttpRequestOptions,
    responseType: new () => T
  ): Promise<T> {
    for (let i = 0; i < this.maxRetries; i++) {
      try {
        return await this.request(config, responseType);
      } catch (error) {
        if (i === this.maxRetries - 1) throw error;
        await this.delay(this.retryDelay * Math.pow(2, i)); // 指数退避
      }
    }
    throw new Error('Max retries exceeded');
  }
}

7. 序列化格式的扩展性 虽然主要使用JSON,但可以设计支持多种序列化格式的插件架构:

interface SerializationFormat {
  serialize<T>(obj: T): string | ArrayBuffer;
  deserialize<T>(data: string | ArrayBuffer, type: new () => T): T;
}

class MultiFormatSerializer {
  private formats: Map<string, SerializationFormat> = new Map();
  
  registerFormat(name: string, format: SerializationFormat): void {
    this.formats.set(name, format);
  }
  
  serialize<T>(format: string, obj: T): string | ArrayBuffer {
    const serializer = this.formats.get(format);
    if (!serializer) throw new Error(`Unsupported format: ${format}`);
    return serializer.serialize(obj);
  }
}

总结: 你的方案已经是一个生产可用的高质量实现。主要优势在于:

  • 完整的类型安全体系
  • 良好的扩展性设计
  • 完善的错误处理
  • 性能优化考虑

在实际项目中,可以根据具体需求选择实现上述优化点。对于大多数应用场景,你现有的方案已经足够优秀。

回到顶部