HarmonyOS 5 网络编程与数据存储实战:从RESTful API到本地持久化

🌐 一、网络编程基础与权限配置

HarmonyOS提供了强大的网络能力,支持HTTP/HTTPS、WebSocket、Socket等协议。

1. 权限声明与配置

module.json5中声明网络权限和加密通信权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_permission_reason"
      },
      {
        "name": "ohos.permission.GET_NETWORK_INFO",
        "reason": "$string:network_info_permission_reason"
      }
    ]
  }
}

2. 网络状态检测

在进行网络请求前,先检测当前网络状态:

import netConnection from '@ohos.net.connection';
import { BusinessError } from '@ohos.base';

class NetworkUtils {
  static async isNetworkAvailable(): Promise<boolean> {
    try {
      const netCap = await netConnection.getDefaultNet();
      if (!netCap) {
        return false;
      }
      
      const netInfo = await netConnection.getConnectionProperties(netCap);
      return netInfo.isAvailable;
    } catch (error) {
      console.error(`Check network failed: ${(error as BusinessError).message}`);
      return false;
    }
  }

  static getNetworkType(): string {
    const netCap = netConnection.getDefaultNetSync();
    return netCap ? netCap.type : 'unknown';
  }
}

📡 二、HTTP/HTTPS 客户端编程

1. 使用 @ohos.net.http模块

import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';

class HttpClient {
  private request: http.HttpRequest = http.createHttp();

  // GET请求示例
  async get<T>(url: string, headers?: Object): Promise<HttpResponse<T>> {
    try {
      if (!await NetworkUtils.isNetworkAvailable()) {
        throw new Error('Network not available');
      }

      const options: http.HttpRequestOptions = {
        method: http.RequestMethod.GET,
        header: headers,
        connectTimeout: 30000,
        readTimeout: 30000
      };

      const response = await this.request.request(url, options);
      
      return {
        code: response.responseCode,
        data: JSON.parse(response.result as string) as T,
        headers: response.header
      };
    } catch (error) {
      throw new Error(`HTTP GET failed: ${(error as BusinessError).message}`);
    }
  }

  // POST请求示例
  async post<T>(url: string, data: Object, headers?: Object): Promise<HttpResponse<T>> {
    try {
      const options: http.HttpRequestOptions = {
        method: http.RequestMethod.POST,
        header: {
          'Content-Type': 'application/json',
          ...headers
        },
        extraData: JSON.stringify(data),
        connectTimeout: 30000,
        readTimeout: 30000
      };

      const response = await this.request.request(url, options);
      
      return {
        code: response.responseCode,
        data: JSON.parse(response.result as string) as T,
        headers: response.header
      };
    } catch (error) {
      throw new Error(`HTTP POST failed: ${(error as BusinessError).message}`);
    }
  }

  // 销毁请求对象
  destroy(): void {
    this.request.destroy();
  }
}

interface HttpResponse<T> {
  code: number;
  data: T;
  headers: Object;
}

2. 实战:天气API调用示例

interface WeatherData {
  city: string;
  temperature: number;
  condition: string;
  humidity: number;
  windSpeed: number;
}

class WeatherService {
  private httpClient: HttpClient = new HttpClient();
  private baseUrl: string = 'https://api.weather.com/v3';

  async getCurrentWeather(city: string): Promise<WeatherData> {
    try {
      const response = await this.httpClient.get<WeatherData>(
        `${this.baseUrl}/current?city=${encodeURIComponent(city)}`
      );

      if (response.code === 200) {
        return response.data;
      } else {
        throw new Error(`Weather API error: ${response.code}`);
      }
    } catch (error) {
      console.error('Failed to fetch weather:', error);
      // 返回缓存数据或默认数据
      return this.getCachedWeatherData(city);
    }
  }

  private getCachedWeatherData(city: string): WeatherData {
    // 从本地存储获取缓存的天气数据
    return {
      city: city,
      temperature: 25,
      condition: 'Cloudy',
      humidity: 60,
      windSpeed: 5
    };
  }
}

3. 文件下载与上传

class FileTransferService {
  private httpClient: HttpClient = new HttpClient();

  // 文件下载
  async downloadFile(url: string, filePath: string): Promise<void> {
    try {
      const options: http.HttpRequestOptions = {
        method: http.RequestMethod.GET,
        connectTimeout: 60000,
        readTimeout: 60000
      };

      const response = await this.httpClient.request(url, options);
      
      if (response.responseCode === 200) {
        // 将文件内容写入本地文件系统
        await this.saveFile(response.result as ArrayBuffer, filePath);
      }
    } catch (error) {
      throw new Error(`Download failed: ${(error as BusinessError).message}`);
    }
  }

  // 文件上传
  async uploadFile(url: string, filePath: string, formData: Object): Promise<void> {
    try {
      const fileContent = await this.readFile(filePath);
      
      const options: http.HttpRequestOptions = {
        method: http.RequestMethod.POST,
        header: {
          'Content-Type': 'multipart/form-data'
        },
        extraData: {
          ...formData,
          file: fileContent
        },
        connectTimeout: 60000,
        readTimeout: 60000
      };

      await this.httpClient.request(url, options);
    } catch (error) {
      throw new Error(`Upload failed: ${(error as BusinessError).message}`);
    }
  }
}

🔌 三、WebSocket 实时通信

对于需要实时数据交换的场景,WebSocket是更好的选择。

import webSocket from '@ohos.net.webSocket';

class WebSocketClient {
  private socket: webSocket.WebSocket | null = null;
  private reconnectAttempts: number = 0;
  private maxReconnectAttempts: number = 5;

  // 连接WebSocket服务器
  async connect(url: string): Promise<void> {
    try {
      this.socket = await webSocket.createWebSocket();
      
      // 注册事件监听器
      this.socket.on('open', () => {
        console.info('WebSocket connected');
        this.reconnectAttempts = 0;
      });

      this.socket.on('message', (data: string | ArrayBuffer) => {
        this.handleMessage(data);
      });

      this.socket.on('close', () => {
        console.info('WebSocket closed');
        this.handleReconnection(url);
      });

      this.socket.on('error', (err: Error) => {
        console.error('WebSocket error:', err);
      });

      // 建立连接
      await this.socket.connect(url);
    } catch (error) {
      console.error('WebSocket connection failed:', error);
      this.handleReconnection(url);
    }
  }

  // 发送消息
  sendMessage(message: string | ArrayBuffer): void {
    if (this.socket && this.socket.readyState === webSocket.ReadyState.OPEN) {
      this.socket.send(message);
    }
  }

  // 处理接收到的消息
  private handleMessage(data: string | ArrayBuffer): void {
    try {
      const message = typeof data === 'string' ? data : new TextDecoder().decode(data);
      const parsedData = JSON.parse(message);
      
      // 分发消息到各个处理器
      this.dispatchMessage(parsedData);
    } catch (error) {
      console.error('Failed to parse WebSocket message:', error);
    }
  }

  // 重连机制
  private handleReconnection(url: string): void {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
      
      setTimeout(() => {
        this.connect(url);
      }, delay);
    }
  }

  // 关闭连接
  close(): void {
    if (this.socket) {
      this.socket.close();
      this.socket = null;
    }
  }
}

💾 四、数据持久化存储

1. 轻量级数据存储(Preferences)

适用于存储简单的键值对数据。

import preferences from '@ohos.data.preferences';

class PreferencesManager {
  private pref: preferences.Preferences | null = null;
  private readonly prefName: string = 'my_app_preferences';

  // 初始化Preferences实例
  async initialize(context: Context): Promise<void> {
    try {
      this.pref = await preferences.getPreferences(context, this.prefName);
    } catch (error) {
      console.error('Failed to initialize preferences:', error);
    }
  }

  // 存储字符串数据
  async putString(key: string, value: string): Promise<boolean> {
    if (!this.pref) return false;
    
    try {
      await this.pref.put(key, value);
      await this.pref.flush();
      return true;
    } catch (error) {
      console.error('Failed to put string:', error);
      return false;
    }
  }

  // 获取字符串数据
  async getString(key: string, defaultValue: string = ''): Promise<string> {
    if (!this.pref) return defaultValue;
    
    try {
      return await this.pref.get(key, defaultValue) as string;
    } catch (error) {
      console.error('Failed to get string:', error);
      return defaultValue;
    }
  }

  // 存储对象数据(自动序列化为JSON)
  async putObject(key: string, value: Object): Promise<boolean> {
    try {
      const jsonString = JSON.stringify(value);
      return await this.putString(key, jsonString);
    } catch (error) {
      console.error('Failed to put object:', error);
      return false;
    }
  }

  // 获取对象数据(自动从JSON反序列化)
  async getObject<T>(key: string, defaultValue: T): Promise<T> {
    try {
      const jsonString = await this.getString(key, '');
      if (jsonString) {
        return JSON.parse(jsonString) as T;
      }
      return defaultValue;
    } catch (error) {
      console.error('Failed to get object:', error);
      return defaultValue;
    }
  }

  // 删除数据
  async delete(key: string): Promise<boolean> {
    if (!this.pref) return false;
    
    try {
      await this.pref.delete(key);
      await this.pref.flush();
      return true;
    } catch (error) {
      console.error('Failed to delete preference:', error);
      return false;
    }
  }

  // 清空所有数据
  async clear(): Promise<boolean> {
    if (!this.pref) return false;
    
    try {
      await this.pref.clear();
      await this.pref.flush();
      return true;
    } catch (error) {
      console.error('Failed to clear preferences:', error);
      return false;
    }
  }
}

2. 关系型数据库(RDB Store)

适用于存储结构化数据,支持SQL查询。

import relationalStore from '@ohos.data.relationalStore';

interface User {
  id?: number;
  name: string;
  email: string;
  age: number;
  createdAt: number;
}

class DatabaseManager {
  private rdbStore: relationalStore.RdbStore | null = null;
  private readonly dbName: string = 'my_app.db';
  private readonly dbVersion: number = 1;

  // 初始化数据库
  async initialize(context: Context): Promise<void> {
    const config: relationalStore.StoreConfig = {
      name: this.dbName,
      securityLevel: relationalStore.SecurityLevel.S1
    };

    try {
      this.rdbStore = await relationalStore.getRdbStore(context, config);
      await this.createTables();
    } catch (error) {
      console.error('Failed to initialize database:', error);
    }
  }

  // 创建数据表
  private async createTables(): Promise<void> {
    if (!this.rdbStore) return;

    const createUserTable = `
      CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        email TEXT UNIQUE NOT NULL,
        age INTEGER,
        created_at INTEGER
      )
    `;

    try {
      await this.rdbStore.executeSql(createUserTable);
    } catch (error) {
      console.error('Failed to create table:', error);
    }
  }

  // 插入用户数据
  async insertUser(user: User): Promise<number> {
    if (!this.rdbStore) return -1;

    const valuesBucket: relationalStore.ValuesBucket = {
      'name': user.name,
      'email': user.email,
      'age': user.age,
      'created_at': Date.now()
    };

    try {
      return await this.rdbStore.insert('users', valuesBucket);
    } catch (error) {
      console.error('Failed to insert user:', error);
      return -1;
    }
  }

  // 查询用户数据
  async queryUsers(query: string = '', params: any[] = []): Promise<User[]> {
    if (!this.rdbStore) return [];

    let sql = 'SELECT * FROM users';
    if (query) {
      sql += ` WHERE ${query}`;
    }

    try {
      const resultSet = await this.rdbStore.query(sql, params);
      const users: User[] = [];

      while (!resultSet.isAtLastRow) {
        await resultSet.goToNextRow();
        users.push({
          id: resultSet.getLong(resultSet.getColumnIndex('id')),
          name: resultSet.getString(resultSet.getColumnIndex('name')),
          email: resultSet.getString(resultSet.getColumnIndex('email')),
          age: resultSet.getLong(resultSet.getColumnIndex('age')),
          createdAt: resultSet.getLong(resultSet.getColumnIndex('created_at'))
        });
      }

      resultSet.close();
      return users;
    } catch (error) {
      console.error('Failed to query users:', error);
      return [];
    }
  }

  // 更新用户数据
  async updateUser(id: number, updates: Partial<User>): Promise<boolean> {
    if (!this.rdbStore) return false;

    const valuesBucket: relationalStore.ValuesBucket = { ...updates };
    const predicates = relationalStore.RdbPredicates('users');
    predicates.equalTo('id', id);

    try {
      const rowsUpdated = await this.rdbStore.update(valuesBucket, predicates);
      return rowsUpdated > 0;
    } catch (error) {
      console.error('Failed to update user:', error);
      return false;
    }
  }

  // 删除用户
  async deleteUser(id: number): Promise<boolean> {
    if (!this.rdbStore) return false;

    const predicates = relationalStore.RdbPredicates('users');
    predicates.equalTo('id', id);

    try {
      const rowsDeleted = await this.rdbStore.delete(predicates);
      return rowsDeleted > 0;
    } catch (error) {
      console.error('Failed to delete user:', error);
      return false;
    }
  }
}

🔄 五、分布式数据管理

HarmonyOS的分布式能力允许数据在多个设备间自动同步。

import distributedKVStore from '@ohos.data.distributedKVStore';

class DistributedDataManager {
  private kvManager: distributedKVStore.KVManager | null = null;
  private kvStore: distributedKVStore.SingleKVStore | null = null;
  private readonly storeId: string = 'distributed_app_data';

  // 初始化分布式数据库
  async initialize(context: Context): Promise<void> {
    try {
      // 创建KVManager实例
      const kvManagerConfig: distributedKVStore.Config = {
        bundleName: context.applicationInfo.name,
        userInfo: {
          userId: '0',
          userType: distributedKVStore.UserType.SAME_USER_ID
        }
      };

      this.kvManager = distributedKVStore.createKVManager(kvManagerConfig);

      // 创建KVStore实例
      const options: distributedKVStore.StoreConfig = {
        storeId: this.storeId,
        kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
        securityLevel: distributedKVStore.SecurityLevel.S2,
        autoSync: true,
        encrypt: false
      };

      this.kvStore = await this.kvManager.getKVStore<distributedKVStore.SingleKVStore>(options);

      // 注册数据变更监听器
      await this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, 
        (data: distributedKVStore.ChangeData) => {
          this.handleDataChange(data);
        });

    } catch (error) {
      console.error('Failed to initialize distributed data manager:', error);
    }
  }

  // 存储数据
  async put(key: string, value: any): Promise<boolean> {
    if (!this.kvStore) return false;

    try {
      const serializedValue = JSON.stringify(value);
      await this.kvStore.put(key, serializedValue);
      return true;
    } catch (error) {
      console.error('Failed to put distributed data:', error);
      return false;
    }
  }

  // 获取数据
  async get(key: string, defaultValue: any = null): Promise<any> {
    if (!this.kvStore) return defaultValue;

    try {
      const entries = await this.kvStore.getEntries(key);
      if (entries.length > 0) {
        const value = entries[0].value.value as string;
        return JSON.parse(value);
      }
      return defaultValue;
    } catch (error) {
      console.error('Failed to get distributed data:', error);
      return defaultValue;
    }
  }

  // 处理数据变更
  private handleDataChange(data: distributedKVStore.ChangeData): void {
    try {
      const changedData = JSON.parse(data.value as string);
      console.info(`Data changed: ${data.key} = ${JSON.stringify(changedData)}`);
      
      // 通知应用其他部分数据已更新
      this.notifyDataChange(data.key, changedData);
    } catch (error) {
      console.error('Failed to handle data change:', error);
    }
  }

  // 数据变更通知
  private notifyDataChange(key: string, newValue: any): void {
    // 使用EventEmitter或其他机制通知应用其他组件
  }
}

🧪 六、实战示例:网络缓存策略

结合网络请求和本地存储实现智能缓存策略。

class CachedApiService {
  private httpClient: HttpClient = new HttpClient();
  private preferences: PreferencesManager = new PreferencesManager();
  private readonly cacheTimeout: number = 5 * 60 * 1000; // 5分钟缓存

  // 获取带缓存的数据
  async getWithCache<T>(url: string, cacheKey: string): Promise<T> {
    // 首先检查缓存
    const cachedData = await this.getFromCache<T>(cacheKey);
    if (cachedData && !this.isCacheExpired(cachedData.timestamp)) {
      return cachedData.data;
    }

    // 缓存无效或不存在,从网络获取
    try {
      const response = await this.httpClient.get<T>(url);
      if (response.code === 200) {
        // 缓存新数据
        await this.saveToCache(cacheKey, response.data);
        return response.data;
      }
      throw new Error(`API returned ${response.code}`);
    } catch (error) {
      // 网络请求失败,返回缓存数据(即使可能过期)
      if (cachedData) {
        console.warn('Using stale cache due to network error');
        return cachedData.data;
      }
      throw error;
    }
  }

  // 从缓存获取数据
  private async getFromCache<T>(key: string): Promise<{ data: T; timestamp: number } | null> {
    try {
      return await this.preferences.getObject(key, null);
    } catch (error) {
      console.error('Failed to get from cache:', error);
      return null;
    }
  }

  // 保存数据到缓存
  private async saveToCache(key: string, data: any): Promise<void> {
    try {
      const cacheItem = {
        data: data,
        timestamp: Date.now()
      };
      await this.preferences.putObject(key, cacheItem);
    } catch (error) {
      console.error('Failed to save to cache:', error);
    }
  }

  // 检查缓存是否过期
  private isCacheExpired(timestamp: number): boolean {
    return Date.now() - timestamp > this.cacheTimeout;
  }

  // 清空特定缓存
  async clearCache(key: string): Promise<void> {
    await this.preferences.delete(key);
  }

  // 清空所有缓存
  async clearAllCache(): Promise<void> {
    await this.preferences.clear();
  }
}

⚠️ 七、安全最佳实践

1. HTTPS证书验证

import ssl from '@ohos.net.ssl';

class SecurityManager {
  static async configureSSL(): Promise<void> {
    try {
      // 加载自定义证书
      const certData = await this.loadCertificate();
      const keyStore = ssl.createX509KeyStore();
      await keyStore.init(certData);

      // 配置SSL选项
      const sslOptions: ssl.SSLOptions = {
        keyStore: keyStore,
        protocols: [ssl.Protocol.TLSV1_2, ssl.Protocol.TLSV1_3],
        cipherSuites: [
          'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',
          'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'
        ]
      };

      // 应用全局SSL配置
      ssl.setSSLOptions(sslOptions);
    } catch (error) {
      console.error('Failed to configure SSL:', error);
    }
  }
}

2. 数据加密存储

import cryptoFramework from '@ohos.security.crypto';

class DataEncryptor {
  private readonly algorithm: string = 'AES256';
  private readonly key: cryptoFramework.SymKey | null = null;

  // 初始化加密密钥
  async initialize(): Promise<void> {
    try {
      const keyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
      const keyOptions: cryptoFramework.SymKeyGeneratorOptions = {
        algName: 'AES256',
        keySize: 256
      };
      
      this.key = await keyGenerator.generateSymKey(keyOptions);
    } catch (error) {
      console.error('Failed to initialize encryptor:', error);
    }
  }

  // 加密数据
  async encrypt(data: string): Promise<string> {
    if (!this.key) throw new Error('Encryptor not initialized');

    try {
      const cipher = cryptoFramework.createCipher('AES256|ECB|PKCS7');
      await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, this.key, null);
      
      const input: cryptoFramework.DataBlob = { data: new TextEncoder().encode(data) };
      const encrypted = await cipher.doFinal(input);
      
      return this.arrayBufferToBase64(encrypted.data);
    } catch (error) {
      throw new Error(`Encryption failed: ${error}`);
    }
  }

  // 解密数据
  async decrypt(encryptedData: string): Promise<string> {
    if (!this.key) throw new Error('Encryptor not initialized');

    try {
      const decipher = cryptoFramework.createCipher('AES256|ECB|PKCS7');
      await decipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, this.key, null);
      
      const input: cryptoFramework.DataBlob = { 
        data: this.base64ToArrayBuffer(encryptedData) 
      };
      const decrypted = await decipher.doFinal(input);
      
      return new TextDecoder().decode(decrypted.data);
    } catch (error) {
      throw new Error(`Decryption failed: ${error}`);
    }
  }
}

通过掌握这些网络编程和数据存储技术,你能够构建出功能丰富、性能优异且数据安全的HarmonyOS应用。这些技术为应用提供了稳定可靠的数据管理和通信能力,是开发现代移动应用的核心基础。

需要参加鸿蒙认证的请点击 鸿蒙认证链接

posted @ 2025-09-24 17:32  猫林老师  阅读(34)  评论(0)    收藏  举报