前言

移动应用的本质是数据消费——从服务器获取数据、提交表单、上传文件,这一切都依赖 HTTP 网络请求。HarmonyOS 提供了 @ohos.net.http 模块,封装了完整的 HTTP 客户端能力,支持 GET/POST 等常见方法、自定义请求头、超时控制、响应解析等核心功能。

相比 Web 端的 fetch / XMLHttpRequest,HarmonyOS 的 HTTP 模块采用了更接近原生网络栈的设计——createHttp() 创建请求任务、request() 发起请求、destroy() 释放资源。这种显式的生命周期管理让开发者对网络连接有更精细的控制。

本文通过一个可交互的 API 请求调试器 Demo,深入讲解 @ohos.net.http 的全部核心 API,涵盖请求配置、响应处理、错误捕获和资源释放。

导入与基础概念

@ohos.net.http@kit.NetworkKit 导入,模块核心是 http 命名空间下的三个关键元素:

import { http } from '@kit.NetworkKit';
元素 类型 说明
http.createHttp() 函数 创建 HTTP 请求任务实例
http.HttpRequest 接口 请求任务对象,提供 requestdestroy 等方法
http.HttpResponse 接口 响应对象,包含 resultresponseCodeheader

createHttp() —— 创建请求任务

一切 HTTP 请求的起点是 createHttp(),它返回一个 HttpRequest 实例:

let httpRequest: http.HttpRequest = http.createHttp();

每个 HttpRequest 实例代表一个独立的网络任务。多次调用 createHttp() 会创建多个互不干扰的任务实例,可以并发发送多个请求。

创建实例后必须在使用完毕后调用 destroy() 释放底层 socket 等系统资源,否则会造成资源泄漏。

HttpRequest.request() —— 发送请求

基础用法(GET 请求)

let httpRequest = http.createHttp();
let response: http.HttpResponse = await httpRequest.request('https://api.example.com/data');
httpRequest.destroy();

不带 options 参数时,默认使用 GET 方法。返回的 HttpResponse 对象包含完整的响应数据。

完整配置(指定方法和请求头)

let httpRequest = http.createHttp();
let options: http.HttpRequestOptions = {
  method: http.RequestMethod.GET,
  connectTimeout: 10000,
  readTimeout: 10000,
  header: {
    'Content-Type': 'application/json',
    'User-Agent': 'HarmonyOS-App/1.0'
  }
};

let response: http.HttpResponse = await httpRequest.request(url, options);

HttpRequestOptions 详细参数

HttpRequestOptions 接口提供了丰富的请求配置选项:

interface HttpRequestOptions {
  method?: RequestMethod;        // 请求方法,默认 GET
  header?: Object;               // 自定义请求头
  extraData?: string | Object | ArrayBuffer; // POST 请求体
  connectTimeout?: number;       // 连接超时(毫秒),默认 60000
  readTimeout?: number;          // 读取超时(毫秒),默认 60000
  expectDataType?: HttpDataType; // 期望的响应数据类型
  usingProtocol?: HttpProtocol;  // 协议类型(HTTP/1.1 或 HTTP/2.0)
  usingCache?: boolean;          // 是否使用缓存
  priority?: number;             // 请求优先级 0-10
  multiFormDataList?: MultiFormData[]; // 多表单数据
  certificatePinning?: CertificatePinning; // 证书锁定
  dnsPrefetch?: string[];        // DNS 预解析
  clientCert?: ClientCert;       // 客户端证书
}

RequestMethod 枚举

enum RequestMethod {
  OPTIONS = 'OPTIONS',
  GET = 'GET',
  HEAD = 'HEAD',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE',
  TRACE = 'TRACE',
  CONNECT = 'CONNECT'
}

POST 请求

发送 POST 请求需要设置 methodextraData

let httpRequest = http.createHttp();
let options: http.HttpRequestOptions = {
  method: http.RequestMethod.POST,
  header: {
    'Content-Type': 'application/json'
  },
  extraData: JSON.stringify({
    title: 'foo',
    body: 'bar',
    userId: 1
  })
};

let response = await httpRequest.request('https://jsonplaceholder.typicode.com/posts', options);
httpRequest.destroy();

extraData 支持三种数据类型:

  • string:纯文本或 JSON 字符串
  • Object:JavaScript 对象(框架会自动序列化)
  • ArrayBuffer:二进制数据(适合上传文件)

超时控制

connectTimeout 控制建立 TCP 连接的最大等待时间,readTimeout 控制等待服务器响应的最大时间。两者都应合理设置——太短会导致慢网络环境下请求频繁失败,太长会让用户等待过久。

let options: http.HttpRequestOptions = {
  connectTimeout: 5000,   // 连接超时 5 秒
  readTimeout: 15000      // 读取超时 15 秒
};

对于需要快速响应的接口(如搜索建议),可以设置更短的超时;对于上传大文件的接口,应该设置更长的超时。
在这里插入图片描述
在这里插入图片描述

HttpResponse —— 响应处理

响应字段

interface HttpResponse {
  result: string | Object | ArrayBuffer; // 响应体
  resultType: HttpDataType;              // 响应体类型标识
  responseCode: number;                  // HTTP 状态码
  header: Object;                        // 响应头
  cookies: string;                       // Cookie 字符串
}

响应体的三种数据类型

result 的类型由 expectDataType 控制:

enum HttpDataType {
  STRING = 0,      // 字符串(默认)
  OBJECT = 1,      // JSON 对象
  ARRAY_BUFFER = 2 // 二进制数据
}

字符串(STRING):最常见的情况,API 返回 JSON 文本时使用。直接用 JSON.parse() 解析:

if (typeof response.result === 'string') {
  let data = JSON.parse(response.result as string);
}

对象(OBJECT):设置 expectDataType: http.HttpDataType.OBJECT 后,框架自动将 JSON 响应解析为对象。通过下标访问字段:

let options: http.HttpRequestOptions = {
  expectDataType: http.HttpDataType.OBJECT
};
let response = await httpRequest.request(url, options);
let result: Object = response.result;
let userId = (result as Record<string, Object>)['userId'];

二进制(ARRAY_BUFFER):适合下载图片、文件等二进制数据。结合 util.TextDecoder 可以转回文本:

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

if (response.result instanceof ArrayBuffer) {
  let decoder = util.TextDecoder.create('utf-8');
  let text = decoder.decodeWithStream(
    new Uint8Array(response.result as ArrayBuffer),
    undefined
  );
}

状态码检查

responseCode 是 HTTP 标准状态码:200 表示成功,2xx 系列均表示成功;4xx 表示客户端错误;5xx 表示服务器错误。

if (response.responseCode === 200) {
  // 成功
} else if (response.responseCode >= 400) {
  // 错误处理
}

注意:HTTP 层面的错误(如 404、500)不会抛出异常,request() 仍然正常返回 HttpResponse,只是 responseCode 不是 2xx。只有网络层面的错误(如 DNS 解析失败、连接超时、TLS 握手失败)才会通过异常抛出。

响应头解析

response.header 是一个键值对对象,通过下标访问:

let header: Object = response.header;
let contentType = (header as Record<string, string>)['content-type'];
let server = (header as Record<string, string>)['server'];

HttpRequest.destroy() —— 资源释放

这是最重要的 API 之一,但开发者经常忽略。每个 HttpRequest 实例持有底层 socket 连接,不及时 destroy() 会导致:

  1. 内存泄漏——未释放的 socket 占用内存
  2. 连接耗尽——系统文件描述符有限,泄露过多会导致新请求失败
  3. 性能退化——后台积累的僵尸连接影响网络栈性能

最佳实践:在 try-finally 中确保始终调用 destroy()

async function fetchData(url: string): Promise<http.HttpResponse | null> {
  let httpRequest: http.HttpRequest | null = null;
  try {
    httpRequest = http.createHttp();
    let response = await httpRequest.request(url);
    return response;
  } catch (err) {
    console.error('请求失败');
    return null;
  } finally {
    if (httpRequest) {
      httpRequest.destroy();
    }
  }
}

on(‘headersReceive’) —— 响应头事件

在请求过程中,可以在 request() 之前注册 headersReceive 事件监听器,在服务器返回响应头(但响应体尚未接收完毕)时触发:

let httpRequest = http.createHttp();

httpRequest.on('headersReceive', (header: Object) => {
  console.info('收到响应头');
  let contentType = (header as Record<string, string>)['content-type'];
});

let response = await httpRequest.request(url);
httpRequest.destroy();

这个事件在以下场景非常有用:

  • 根据 content-type 提前决定如何解析响应体
  • 根据 content-length 计算下载进度
  • 记录请求耗时(在事件中计算与请求开始的时间差)

错误处理

HTTP 模块的异常分为两类:

1. 网络层异常(抛出错误)

以下情况会通过 catch 捕获:

try {
  let response = await httpRequest.request(url);
} catch (err) {
  let errObj = err as Object;
  let rec = errObj as Record<string, Object>;
  let message = rec['message'] as string;
  // 常见错误信息:
  // - "Couldn't resolve host name" → DNS 解析失败
  // - "Timeout was reached" → 超时
  // - "SSL certificate problem" → TLS 证书问题
  // - "Failed to connect to" → 服务器不可达
}

2. HTTP 层错误(正常响应)

4xx 和 5xx 状态码不会抛出异常,需要检查 responseCode

let response = await httpRequest.request(url);
if (response.responseCode >= 200 && response.responseCode < 300) {
  // 成功处理
} else if (response.responseCode === 404) {
  // 资源不存在
} else if (response.responseCode >= 500) {
  // 服务器错误
}

性能与安全建议

1. 实例复用

同一个域名下的多次请求可以复用 HttpRequest 实例,底层会复用 TCP 连接(HTTP Keep-Alive):

// 推荐:复用同一个实例
let httpRequest = http.createHttp();
for (let url of urls) {
  let response = await httpRequest.request(url);
}
httpRequest.destroy();

// 不推荐:每次都创建新实例(浪费连接)
for (let url of urls) {
  let req = http.createHttp();
  let response = await req.request(url);
  req.destroy();
}

2. HTTPS 证书安全

生产环境应当严格验证 HTTPS 证书。HarmonyOS 默认启用系统 CA 证书库验证,这是最安全的配置。开发阶段如果遇到自签名证书,可以在测试环境使用以下配置,但绝对不能用于生产环境

// 仅开发调试用,切勿在生产代码中使用
let options: http.HttpRequestOptions = {
  remoteValidation: 'skip' // 跳过证书验证(危险!)
};

3. DNS 预解析

对于已知的目标域名,可以在应用启动时预解析 DNS,减少首次请求的延迟:

let options: http.HttpRequestOptions = {
  dnsPrefetch: ['api.example.com', 'cdn.example.com']
};

4. 请求优先级

当同时发起多个请求时,可以设置优先级让重要请求优先获得网络资源:

let options: http.HttpRequestOptions = {
  priority: 5  // 0(最低)到 10(最高)
};

Demo:API 请求调试器

我们构建了一个完整的 HTTP 请求调试工具,可以在真机或模拟器上实际发送网络请求并查看响应。

功能模块

  1. URL 输入与快捷 API:输入任意 URL,或点击预设的 3 个 JSONPlaceholder API 快速填充
  2. GET/POST 方法切换:可视化按钮切换,GET 蓝色、POST 粉色
  3. 发送请求与加载状态:按钮在请求中显示"请求中…"并禁用,防止重复发送
  4. 响应摘要卡片:展示状态码(绿色=2xx,红色=错误,橙色=其他)、请求方法、耗时
  5. 响应头显示:解析并显示前 10 个响应头
  6. 响应体预览:等宽字体、可滚动文本框,超过 2000 字符自动截断并标注完整长度
  7. 请求历史:记录最近 15 条请求的序号、方法、URL、状态码和时间

核心发送逻辑

async sendRequest(): Promise<void> {
  this.isLoading = true;
  let startTime: number = Date.now();
  let httpRequest: http.HttpRequest | null = null;

  try {
    httpRequest = http.createHttp();
    let options: http.HttpRequestOptions = {
      method: this.methods[this.methodIndex] === 'POST'
        ? http.RequestMethod.POST : http.RequestMethod.GET,
      connectTimeout: 10000,
      readTimeout: 10000,
      header: {
        'Content-Type': 'application/json',
        'User-Agent': 'HarmonyOS-HttpDemo/1.0'
      }
    };

    let response: http.HttpResponse = await httpRequest.request(
      this.urlInput.trim(), options
    );
    let elapsed: number = Date.now() - startTime;

    this.statusCode = response.responseCode.toString();
    this.responseTime = elapsed + 'ms';

    // 解析响应体
    if (typeof response.result === 'string') {
      this.responseBody = response.result as string;
    } else if (response.result instanceof ArrayBuffer) {
      let decoder = util.TextDecoder.create('utf-8');
      this.responseBody = decoder.decodeWithStream(
        new Uint8Array(response.result as ArrayBuffer), undefined
      );
    } else {
      this.responseBody = JSON.stringify(response.result);
    }

    // 解析响应头
    if (response.header) {
      let hdr: Object = response.header;
      let headerStr: string = '';
      let keys: string[] = Object.keys(hdr);
      for (let i = 0; i < Math.min(keys.length, 10); i++) {
        headerStr += keys[i] + ': ' +
          (hdr as Record<string, string>)[keys[i]] + '\n';
      }
      this.responseHeaders = headerStr;
    }

    this.addHistory(this.methods[this.methodIndex],
      this.urlInput.trim(), response.responseCode.toString());

  } catch (err) {
    this.statusCode = 'ERROR';
    let rec: Record<string, Object> = err as Record<string, Object>;
    this.responseBody = '错误: ' + (rec['message'] as string);
    this.addHistory(this.methods[this.methodIndex],
      this.urlInput.trim(), 'FAIL');
  } finally {
    if (httpRequest) {
      httpRequest.destroy();
    }
    this.isLoading = false;
  }
}

请求历史管理

使用不可变状态更新模式维护最近 15 条记录:

addHistory(method: string, url: string, status: string): void {
  this.historyIndex++;
  let record = new RequestRecord(
    this.historyIndex, method, url, status,
    new Date().toLocaleTimeString()
  );
  let newHistory: RequestRecord[] = [record].concat(this.history);
  if (newHistory.length > 15) {
    newHistory.pop();
  }
  this.history = newHistory;
}

注意事项

Demo 使用的 jsonplaceholder.typicode.com 是一个公开的测试 API,返回模拟数据。在实际应用开发中,你需要:

  1. 申请网络权限:在 module.json5 中添加 ohos.permission.INTERNET
  2. 配置网络安全:生产环境使用 HTTPS,开发调试可在 module.json5 中配置 networkSecurity
  3. 处理大响应:Demo 截断 2000 字符以上的响应,实际应用中应流式处理大文件下载

总结

本文详细讲解了 HarmonyOS @ohos.net.http 模块的核心 API:

  1. createHttp() — 创建请求任务,返回 HttpRequest 实例
  2. HttpRequest.request() — 发送请求,支持 GET/POST 等方法、自定义请求头、超时控制
  3. HttpResponse — 响应处理,支持字符串/对象/二进制三种数据类型
  4. HttpRequest.destroy() — 资源释放,务必在请求完成后调用
  5. on(‘headersReceive’) — 响应头事件,提前获取元数据
  6. 错误处理 — 区分网络层异常(catch)和 HTTP 层错误(responseCode)

HarmonyOS 的 HTTP 模块提供了完整的网络请求能力,其 API 设计强调显式资源管理,通过 createHttp/destroy 配对确保不泄露系统资源。结合 Promise 异步模型,可以写出清晰、可维护的网络层代码。

API 请求调试器 Demo 是一个实用的开发工具,不仅展示 HTTP 模块的使用方式,本身也可以用于日常调试第三方 API 接口。


Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐