<canvas_command><action>create</action><identifier>hongmeng-electron-network-request-guide</identifier>

<title>鸿蒙 Electron 网络请求实战:HTTP/HTTPS 调用、跨域解决、异常处理</title><genre>实战教程</genre><type>type/ddxml</type><content><title id="0">鸿蒙 Electron 网络请求实战:HTTP/HTTPS 调用、跨域解决、异常处理</title><p id="1">鸿蒙 Electron 应用开发中,网络请求是对接后端服务、实现数据交互的核心能力。与传统 Web 应用相比,鸿蒙 Electron 因“主进程+渲染进程”的架构特性,在网络请求时需处理权限配置、跨域限制、系统拦截等特殊问题。本文聚焦生产级开发场景,从基础配置到架构设计,再到异常处理,逐步拆解 HTTP/HTTPS 调用、跨域解决方案、断网处理、超时重试等核心需求,提供高质量、可直接复用的代码案例,帮助开发者快速搭建健壮的网络请求体系。</p>

<callout id="2" emoji="⚠️">
核心认知:① 鸿蒙系统对网络请求有严格权限管控,未声明权限会直接拦截请求;② 渲染进程请求受浏览器跨域规则限制,主进程请求无跨域问题;③ 网络请求需兼顾鸿蒙设备兼容性与Electron架构特性,推荐"主进程代理"方案。
</callout>

<h1 id="3">一、基础准备:鸿蒙网络权限配置与依赖安装</h1>
<p id="4">网络请求前需完成两项基础操作:声明鸿蒙系统网络权限(避免请求被拦截)、安装网络请求依赖(选用axios作为核心库)。</p>

<h2 id="5">1.1 鸿蒙网络权限配置(config.json)</h2>
<p id="6">在项目根目录的 <code id="7">config.json 中声明网络权限、域名白名单,允许HTTP/HTTPS请求:

{
  "app": {
    "bundleName": "com.example.networkdemo",
    "version": { "code": 1000000, "name": "1.0.0" }
  },
  "module": {
    "name": "entry",
    "mainAbility": "MainAbility",
    "deviceType": ["phone", "pc", "tv"],
    // 1. 声明网络权限
    "reqPermissions": [{
      "name": "ohos.permission.INTERNET", // 核心网络权限
      "reason": "访问后端API服务,实现数据交互", // 权限申请理由(用户可见)
      "usedScene": {
        "ability": ["com.example.networkdemo.MainAbility"],
        "when": "always" // 始终需要该权限
      }
    }],
    // 2. 网络请求配置(域名白名单+明文请求控制)
    "network": {
      "cleartextTraffic": true, // 开发环境允许HTTP明文请求(生产环境建议关闭)
      "domainSettings": {
        "domains": [
          { "domain": "api.example.com", "type": "normal" }, // 后端API域名(必配)
          { "domain": "*.example.com", "type": "normal" }, // 通配符支持(子域名)
          { "domain": "api.github.com", "type": "normal" } // 第三方API域名
        ]
      }
    }
  }
}

关键说明:① ohos.permission.INTERNET 是网络请求的核心权限,缺失会导致所有请求失败;② 域名白名单需填写实际对接的后端域名;③ 生产环境应将 cleartextTraffic 设为 false,仅允许HTTPS请求。

plaintext

&#x3C;h2 id=&#x22;14&#x22;&#x3E;1.2 &#x4F9D;&#x8D56;&#x5B89;&#x88C5;&#xFF08;axios&#xFF09;&#x3C;/h2&#x3E;
&#x3C;p id=&#x22;15&#x22;&#x3E;axios &#x662F;&#x524D;&#x7AEF;&#x751F;&#x6001;&#x4E2D;&#x6700;&#x6210;&#x719F;&#x7684;&#x7F51;&#x7EDC;&#x8BF7;&#x6C42;&#x5E93;&#xFF0C;&#x652F;&#x6301;&#x62E6;&#x622A;&#x5668;&#x3001;&#x8D85;&#x65F6;&#x63A7;&#x5236;&#x3001;&#x53D6;&#x6D88;&#x8BF7;&#x6C42;&#x7B49;&#x6838;&#x5FC3;&#x529F;&#x80FD;&#xFF0C;&#x9E3F;&#x8499; Electron &#x4E2D;&#x53EF;&#x76F4;&#x63A5;&#x5B89;&#x88C5;&#x4F7F;&#x7528;&#xFF1A;&#x3C;/p&#x3E;
&#x3C;pre id=&#x22;16&#x22;&#x3E;&#x3C;code id=&#x22;17&#x22; lang=&#x22;bash&#x22;&#x3E;# &#x8FDB;&#x5165;&#x9879;&#x76EE;&#x6839;&#x76EE;&#x5F55;

cd your-project-name

安装 axios(推荐使用稳定可靠的 1.x 版本) npm install axios@1.6.8 --save

为 TypeScript 项目安装类型声明文件(必需) npm install @types/axios --save-dev

二、架构设计:生产级网络请求体系(主进程代理方案)

推荐采用"渲染进程调用 → IPC通信 → 主进程代理请求"的分层架构,具有以下核心优势:

  1. 规避渲染进程跨域问题
  2. 统一权限控制与异常处理
  3. 便于扩展请求监控、加密等功能

整体架构流程: 渲染进程API封装 → 预加载脚本暴露接口 → 主进程IPC监听 → 主进程网络请求核心 → 后端服务

2.1 主进程:网络请求核心封装(含拦截器、异常处理)

在主进程中创建网络请求服务,集成以下核心能力:

  • 请求/响应拦截器
  • 超时重试机制
  • 断网检测功能
// src/main/services/networkService.ts
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { app } from '@hmos/electron';
import { networkInterfaces } from 'os';
import path from 'path';
import fs from 'fs/promises';

// 1. 创建axios实例(主进程无跨域限制)
const apiClient = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json;charset=utf-8',
    'User-Agent': `HarmonyElectron/${app.getVersion()}-${process.platform}`
  }
});

// 2. 请求拦截器:统一添加请求头、认证信息
apiClient.interceptors.request.use(async (config: AxiosRequestConfig) => {
  // 自动添加认证Token
  const tokenPath = path.join(app.getPath('userData'), 'auth-token.json');
  try {
    const tokenContent = await fs.readFile(tokenPath, 'utf8');
    const { token } = JSON.parse(tokenContent);
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
  } catch (error) {
    console.log('未找到认证Token,继续无认证请求');
  }

  // 添加请求ID
  config.headers['X-Request-Id'] = Date.now() + '-' + Math.random().toString(36).substr(2, 9);
  return config;
}, (error: AxiosError) => {
  console.error('请求参数异常:', error.config?.data, error.message);
  return Promise.reject({ code: 'REQUEST_PARAM_ERROR', message: error.message });
});

// 3. 响应拦截器:统一异常处理、数据格式化
apiClient.interceptors.response.use((response: AxiosResponse) => {
  const { data } = response;
  if (data.code !== 0) {
    return Promise.reject({
      code: data.code,
      message: data.message || '业务处理失败',
      rawData: data
    });
  }
  return data.data;
}, (error: AxiosError) => {
  const { config, response, request } = error;

  // 4. 断网检测
  if (!checkNetworkStatus()) {
    return Promise.reject({ code: 'NETWORK_DISCONNECTED', message: '网络连接已断开,请检查网络设置' });
  }

  // 5. 超时重试机制
  if (error.code === 'ECONNABORTED' && config?.['retryCount'] < 3) {
    const retryCount = (config?.['retryCount'] || 0) + 1;
    const retryDelay = retryCount * 1000;
    console.log(`请求超时,正在进行第${retryCount}次重试(延迟${retryDelay}ms)`, config.url);
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(apiClient({ ...config, retryCount }));
      }, retryDelay);
    });
  }

  // 6. HTTP状态码错误处理
  const status = response?.status;
  let errorMsg = '网络请求失败';
  switch (status) {
    case 401:
      errorMsg = '登录已过期,请重新登录';
      break;
    case 403:
      errorMsg = '权限不足,无法访问该资源';
      break;
    case 404:
      errorMsg = '请求的资源不存在';
      break;
    case 500:
    case 502:
    case 503:
      errorMsg = '服务器内部错误,请稍后重试';
      break;
    default:
      errorMsg = error.message || '未知网络错误';
  }

  // 7. 记录错误日志
  console.error(`[NETWORK_ERROR] ${config?.method?.toUpperCase()} ${config?.url} | 状态码: ${status} | 错误: ${errorMsg}`, error.stack);
  return Promise.reject({ code: status });
## 2.2 主进程:IPC 通信监听(对接渲染进程)

主进程通过 IPC 监听渲染进程的请求,调用网络请求服务并将结果返回给渲染进程:

```typescript
// src/main/ipc/networkIpc.ts
import { ipcMain } from '@hmos/electron';
import { http, checkNetworkStatus } from '../services/networkService';

// 注册网络相关 IPC 处理器(统一管理)
export const registerNetworkIpcHandlers = () => {
  // 1. 通用网络请求接口(支持所有 HTTP 方法)
  ipcMain.handle('network-request', async (_, options) => {
    try {
      const { method = 'GET', url, params, data, config } = options;
      let result;

      // 根据请求方法调用对应 http 函数
      switch (method.toUpperCase()) {
        case 'GET':
          result = await http.get(url, params, config);
          break;
        case 'POST':
          result = await http.post(url, data, config);
          break;
        case 'PUT':
          result = await http.put(url, data, config);
          break;
        case 'DELETE':
          result = await http.delete(url, params, config);
          break;
        default:
          throw new Error(`不支持的请求方法: ${method}`);
      }

      // 成功响应格式
      return { success: true, data: result };
    } catch (error) {
      // 失败响应格式(与渲染进程约定)
      return {
        success: false,
        error: {
          code: error.code || 'UNKNOWN_ERROR',
          message: error.message || '网络请求失败'
        }
      };
    }
  });

  // 2. 网络状态检测接口(单独暴露,便于渲染进程预检测)
  ipcMain.handle('check-network-status', async () => {
    return { online: checkNetworkStatus(), timestamp: Date.now() };
  });
};

2.3 预加载脚本:暴露安全通信接口(preload.js)

预加载脚本运行在渲染进程上下文与主进程上下文之间,通过 contextBridge 向渲染进程暴露安全的 IPC 通信接口,避免渲染进程直接访问敏感 API:

// src/common/preload.js
import { contextBridge, ipcRenderer } from '@hmos/electron';

// 向渲染进程暴露网络请求相关接口(白名单机制)
contextBridge.exposeInMainWorld('networkApi', {
  // 通用网络请求
  request: (options) => ipcRenderer.invoke('network-request', options),
  // 网络状态检测
  checkStatus: () => ipcRenderer.invoke('check-network-status')
});

// TypeScript 类型声明(可选,提升开发体验)
declare global {
  interface Window {
    networkApi: {
      request: (options: {
        method?: string;
        url: string;
        params?: any;
        data?: any;
        config?: any;
      }) => Promise<{
        success: boolean;
        data?: any;
        error?: { code: string | number; message: string };
      }>;
      checkStatus: () => Promise<{ online: boolean; timestamp: number }>;
    };
  }
}

2.4 渲染进程:API 封装(业务层调用)

在渲染进程中封装业务 API,统一调用预加载脚本暴露的接口,避免重复代码,提升可维护性:

// src/renderer/services/api.ts
import { Ref } from 'vue';

// 1. 类型定义(TypeScript 项目必配,确保类型安全)
// 响应结果类型(与主进程约定)
interface ApiResponse<T> {
  success: boolean;
  data?: T;
  error?: { code: string | number; message: string };
}

// 业务数据类型示例
export interface UserInfo {
  id: string;
  name: string;
  email: string;
  avatar: string;
  createTime: string;
}

export interface PageResult

欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/

Logo

赋能鸿蒙PC开发者,共建全场景原生生态,共享一次开发多端部署创新价值。

更多推荐