Harmony os HTTP 网络访问(Network Kit 版)

Harmony os HTTP 网络访问(Network Kit 版)

写给未来的自己:这就是我以后写接口 / 下大文件 / 配 HTTPS 时要翻的那份笔记。


1. HTTP 能力总览

HarmonyOS 里访问网络主要靠 Network Kit 的 http 模块

  • 支持方法:GET / POST / PUT / DELETE / OPTIONS / HEAD / TRACE / CONNECT
  • 提供两种请求方式:
    • httpRequest.request:普通请求,小数据量接口
    • httpRequest.requestInStream:流式传输,大文件上传下载 + 进度

额外一条:

如果是"跨设备协同场景",可以考虑 Remote Communication Kit,它是更偏远程调用那条线,这里不展开。


2. 普通 HTTP 请求使用流程

2.1 导入模块 & 获取上下文

复制代码
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';

let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;

2.2 创建 HttpRequest 对象

一个 httpRequest 对象 对应一个请求,用完直接销毁,不要复用。

复制代码
const httpRequest = http.createHttp();

2.3 (可选)订阅响应头事件

headersReceive 会在 完整响应之前触发,适合先看 header 再决定后续处理方式。

复制代码
httpRequest.on('headersReceive', (header) => {
  console.info('header: ' + JSON.stringify(header));
});

从 API 8 开始,统一用 on('headersReceive', cb),不要再用老的 headerReceive

2.4 发起请求:request(url, options, callback)

常规 POST 请求笔记版示例:

复制代码
httpRequest.request(
  'EXAMPLE_URL',
  {
    method: http.RequestMethod.POST,           // 默认是 GET
    header: {
      'Content-Type': 'application/json'       // POST/PUT/DELETE/"" 默认就是 application/json
    },
    extraData: "data to send",                 // 请求体,格式跟后端约定
    expectDataType: http.HttpDataType.STRING,  // 指定返回数据类型,可选
    usingCache: true,                          // 是否使用缓存(进程级),默认 true
    priority: 1,                               // 并发优先级 [1,1000],越大越高
    connectTimeout: 60000,                     // 连接超时,默认 60000ms
    readTimeout: 60000,                        // 总读取超时(包含 DNS/连接/传输)
    usingProtocol: http.HttpProtocol.HTTP1_1,  // 协议版本,默认系统自动选
    usingProxy: false,                         // 10+,是否使用系统或自定义代理
    caPath: '/path/to/cacert.pem',             // 10+,自定义 CA 证书路径
    clientCert: {                              // 11+,客户端证书(双向 TLS)
      certPath: '/path/to/client.pem',
      keyPath: '/path/to/client.key',
      certType: http.CertType.PEM,
      keyPassword: 'passwordToKey'
    },
    // 11+,multipart/form-data 上传字段列表
    multiFormDataList: [
      {
        name: 'Part1',
        contentType: 'text/plain',
        data: 'Example data',
        remoteFileName: 'example.txt',
      },
      {
        name: 'Part2',
        contentType: 'text/plain',
        filePath: `${context.filesDir}/fileName.txt`,
        remoteFileName: 'fileName.txt',
      },
      {
        name: 'Part3',
        contentType: 'image/png',
        filePath: `${context.filesDir}/fileName.png`,
        remoteFileName: 'fileName.png',
      },
    ],
  },
  (err: BusinessError, data: http.HttpResponse) => {
    if (!err) {
      console.info('Result: ' + JSON.stringify(data.result));
      console.info('Code: ' + JSON.stringify(data.responseCode));
      console.info('Header: ' + JSON.stringify(data.header));
      console.info('Cookies: ' + JSON.stringify(data.cookies)); // 8+
      httpRequest.destroy();          // ✅ 请求结束别忘了销毁
    } else {
      console.error('error: ' + JSON.stringify(err));
      httpRequest.off('headersReceive'); // 取消订阅
      httpRequest.destroy();
    }
  }
);

2.5 取消订阅 & 销毁

口诀:用完就 off + destroy,不要拖。

复制代码
httpRequest.off('headersReceive');
httpRequest.destroy();

3. 流式 HTTP:大文件 & 进度控制

3.1 典型使用场景

  • 下载大文件(视频、安装包、离线资源包)
  • 上传大文件(日志、数据备份)
  • 需要实时展示进度条
  • 不想一次把数据全塞进内存

3.2 创建 HttpRequest

复制代码
import { http } from '@kit.NetworkKit';

const httpRequest = http.createHttp();  // 一样:一任务一对象

3.3 订阅流式事件

复制代码
let res = new ArrayBuffer(0);

// 实时接收数据块
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
  const newRes = new ArrayBuffer(res.byteLength + data.byteLength);
  const resView = new Uint8Array(newRes);
  resView.set(new Uint8Array(res));
  resView.set(new Uint8Array(data), res.byteLength);
  res = newRes;
  console.info('res length: ' + res.byteLength);
});

// 全部数据接收完毕
httpRequest.on('dataEnd', () => {
  console.info('No more data in response, data receive end');
});

// 下载进度
httpRequest.on('dataReceiveProgress', (info: http.DataReceiveProgressInfo) => {
  console.info('dataReceiveProgress receiveSize:' + info.receiveSize + ', totalSize:' + info.totalSize);
});

// 上传进度
httpRequest.on('dataSendProgress', (info: http.DataSendProgressInfo) => {
  console.info('dataSendProgress sendSize:' + info.sendSize + ', totalSize:' + info.totalSize);
});

实战里我会在 dataReceive 里直接把数据写到文件,而不是累积在内存里,看场景选择。

3.4 发起流式请求:requestInStream

复制代码
let streamInfo: http.HttpRequestOptions = {
  method: http.RequestMethod.POST,
  header: {
    'Content-Type': 'application/json'
  },
  extraData: "data to send",
  expectDataType: http.HttpDataType.STRING,
  usingCache: true,
  priority: 1,
  connectTimeout: 60000,
  readTimeout: 60000, // 大文件建议加大一点
  usingProtocol: http.HttpProtocol.HTTP1_1,
};

httpRequest.requestInStream('EXAMPLE_URL', streamInfo)
  .then((code: number) => {
    console.info('requestInStream OK!');
    console.info('ResponseCode: ' + code);
    destroyRequest(httpRequest);
  })
  .catch((err: Error) => {
    console.error('requestInStream ERROR: ' + JSON.stringify(err));
    destroyRequest(httpRequest);
  });

3.5 统一封装销毁逻辑

复制代码
function destroyRequest(httpRequest: http.HttpRequest) {
  httpRequest.off('dataReceive');
  httpRequest.off('dataSendProgress');
  httpRequest.off('dataReceiveProgress');
  httpRequest.off('dataEnd');
  httpRequest.destroy();
}

4. HTTPS 证书相关配置笔记

场景:要么是自己做了证书锁定(pinning),要么是不想信任用户乱装的 CA,要么是测试环境想先跳过校验。

所有网络安全相关配置都写在:

复制代码
src/main/resources/base/profile/network_config.json

4.1 证书锁定(Pinning)两种方式

方式 1:预置证书文件

  • 支持 .crt / .pem 格式;
  • 然后在 network_config.json 里配置这个证书与域名的绑定关系。

简化例子(信任特定路径下证书):

复制代码
{
  "network-security-config": {
    "base-config": {
      "trust-anchors": [
        {
          "certificates": "/etc/security/certificates"
        }
      ]
    },
    "domain-config": [
      {
        "domains": [
          {
            "include-subdomains": true,
            "name": "example.com"
          }
        ],
        "trust-anchors": [
          {
            "certificates": "/data/storage/el1/bundle/entry/resources/resfile"
          }
        ]
      }
    ]
  }
}

方式 2:预置证书公钥哈希(推荐更灵活)

  • 到服务器拿到证书(OpenSSL 命令获取 .pem);
  • 从证书中提取公钥,算 SHA256,再 base64;
  • 把这个 digest 写入 pin-set

简化例子:

复制代码
{
  "network-security-config": {
    "domain-config": [
      {
        "domains": [
          {
            "include-subdomains": true,
            "name": "*.server.com"
          }
        ],
        "pin-set": {
          "expiration": "2024-11-08",
          "pin": [
            {
              "digest-algorithm": "sha256",
              "digest": "FEDCBA987654321"
            }
          ]
        }
      }
    ]
  }
}

注意:证书链上任意一本证书变了,锁定都可能失败 → 服务器更新证书时,App 网络配置也要同步更新。

4.2 不信任用户安装的 CA 证书

默认:系统预置 CA + 用户安装 CA 都信任。

想要 更严安全策略:关掉两类用户 CA 信任。

复制代码
{
  "network-security-config": {
    // ...你的其他配置
  },
  "trust-global-user-ca": false,  // 不信任 MDM/管理员安装 CA
  "trust-current-user-ca": false  // 不信任当前用户自己装的 CA
}

5. 明文 HTTP(非 HTTPS)访问控制

开关大意:是否允许明文 HTTP,可按应用、域名、组件粒度控制。

5.1 优先级规则

  • component-config > domain-config > base-config
  • 越具体的优先级越高,后者覆盖前者。

5.2 配置示例

复制代码
{
  "network-security-config": {
    "base-config": {
      "cleartextTrafficPermitted": true // 应用默认允许 HTTP(API 20+)
    },
    "domain-config": [
      {
        "domains": [
          {
            "include-subdomains": true,
            "name": "example.com"
          }
        ],
        "cleartextTrafficPermitted": false // 对 example.com 禁 HTTP
      }
    ],
    "component-config": {
      "Network Kit": true, // Network Kit 支持禁止明文
      "ArkWeb": false      // ArkWeb 不支持禁止明文
    }
  }
}

字段速记:

  • cleartextTrafficPermitted: 是否允许 HTTP 明文传输(默认 true)
  • Network Kit / ArkWeb: 这个组件是否参与"禁止明文"控制

6. 我自己的使用习惯小结

最后给自己留几条 checklist:

  1. 一请求一 HttpRequest,所有销毁逻辑统一封在工具函数里
  2. 普通接口用 request + expectDataType 即可
  3. 大文件(下载/上传)一律走 requestInStream + 进度回调
  4. 正式环境把 network_config.json 安全相关配置补全:
    • 哪些域名要做证书锁定;
    • 是否需要禁用用户 CA;
    • 是否逐步禁用 HTTP 明文。
  5. 调试阶段策略可以宽一点,打包发布前再收紧
相关推荐
游戏开发爱好者81 小时前
iOS 应用上架的工程实践复盘,从构建交付到审核通过的全流程拆解
android·ios·小程序·https·uni-app·iphone·webview
遇到困难睡大觉哈哈1 小时前
Harmony os ArkTS 卡片生命周期管理:我怎么把 EntryFormAbility 用顺手的
前端·harmonyos·鸿蒙
00后程序员张1 小时前
iOS App 如何上架,从准备到发布的完整流程方法论
android·macos·ios·小程序·uni-app·cocoa·iphone
5***V9331 小时前
SQL 注入漏洞原理以及修复方法
网络·数据库·sql
Wokoo71 小时前
数据链路层:以太网、MAC 地址及 ARP 协议详解
服务器·网络·后端·网络协议·信号处理
有泽改之_1 小时前
Garmin FIT协议与FIT Activity文件类型
网络·python
jenchoi4131 小时前
【2025-11-27】软件供应链安全日报:最新漏洞预警与投毒预警情报汇总
网络·安全·web安全·网络安全·npm
q***01651 小时前
Node.js HTTP模块详解:创建服务器、响应请求与客户端请求
服务器·http·node.js
遇到困难睡大觉哈哈1 小时前
HarmonyOS IPC/RPC 实战:用 ArkTS 跑通 Proxy–Stub 整条链路
qt·rpc·harmonyos·鸿蒙