引言

网络请求是移动应用中最基础也最频繁的操作之一。无论是获取服务端数据、提交表单、上传文件还是调用第三方 API,都离不开 HTTP 客户端。HarmonyOS NEXT 通过 @ohos.net.http 模块为开发者提供了一套完整的 HTTP 客户端能力,覆盖从创建请求实例到处理响应结果的全生命周期。

@ohos.net.http 属于 @kit.NetworkKit,与 Android 的 HttpURLConnection 和 iOS 的 URLSession 定位类似,但 API 设计更加简洁直观。它的核心流程可以概括为三步:创建实例 → 发起请求 → 销毁实例。所有请求通过 Promise 异步返回,天然支持链式调用和 async/await 语法。

本文将深入讲解 @ohos.net.http 的 API 体系、请求构建、响应处理、超时配置和错误处理策略,并构建一个"网络请求实验室"Demo,让你在一个页面中完整体验 GET、POST、PUT、DELETE 四种常用方法的请求构建、参数配置和响应展示。

一、API 架构:以 HttpRequest 为核心的三步模式

1.1 核心设计理念

@ohos.net.http 的 API 设计遵循"创建 - 使用 - 销毁"的生命周期模式:

  1. 创建:通过 createHttp() 获取一个 HttpRequest 实例
  2. 使用:通过 request(url, options) 发送请求并获取 HttpResponse
  3. 销毁:通过 destroy() 释放底层资源

这种设计与 Java 的 HttpURLConnectionopenConnection() → connect() → disconnect() 模式一脉相承,但通过 Promise 封装消除了回调地狱。

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

// 三步标准模式
const httpReq = http.createHttp();
httpReq.request('https://api.example.com/data', {
  method: http.RequestMethod.GET,
  expectDataType: http.HttpDataType.STRING,
  connectTimeout: 10000,
  readTimeout: 10000
}).then((resp) => {
  console.log('状态码:', resp.responseCode);
  console.log('响应体:', resp.result);
}).catch((e: Error) => {
  console.error('请求失败:', e.message);
}).finally(() => {
  httpReq.destroy();  // 必须销毁
});

1.2 HttpRequest —— 请求任务实例

createHttp() 返回的 HttpRequest 对象代表一个 HTTP 任务实例。每个实例维护自己的连接池和配置,应当在使用完毕后调用 destroy() 销毁。

HttpRequest 的核心方法:

方法说明
request(url, options?)发起 HTTP 请求,返回 Promise<HttpResponse>
destroy()销毁实例,释放连接资源
on('headersReceive', callback)监听响应头接收事件
off('headersReceive', callback?)取消监听响应头事件

1.3 HttpRequestOptions —— 请求配置

HttpRequestOptions 是请求配置的核心数据结构:

interface HttpRequestOptions {
  method?: RequestMethod;          // 请求方法,默认 GET
  header?: Object;                 // 请求头,键值对
  extraData?: string | ArrayBuffer; // 请求体(POST/PUT 使用)
  expectDataType?: HttpDataType;   // 期望的响应数据类型
  connectTimeout?: number;         // 连接超时(ms),默认 60000
  readTimeout?: number;            // 读取超时(ms),默认 60000
  usingProtocol?: HttpProtocol;    // 使用的协议(HTTP/1.1 或 HTTP/2)
  usingProxy?: boolean | Object;   // 是否使用代理
  caPath?: string;                 // CA 证书路径(HTTPS 双向认证)
  clientCert?: ClientCert;         // 客户端证书
}

在我们的 Demo 中,最小配置只需要 methodexpectDataType

const options: http.HttpRequestOptions = {
  method: http.RequestMethod.GET,
  header: { 'Content-Type': 'application/json' },
  expectDataType: http.HttpDataType.STRING,
  connectTimeout: 10000,
  readTimeout: 10000
};

1.4 RequestMethod —— 请求方法枚举

RequestMethod 枚举定义了 HTTP 方法:

枚举值说明
GET获取资源
POST创建资源
PUT更新资源(全量)
DELETE删除资源
HEAD获取响应头(无响应体)
OPTIONS查询服务器支持的方法
PATCH更新资源(部分)
CONNECT建立隧道连接
TRACE回显请求用于诊断

最常用的是 GET、POST、PUT、DELETE,也是 Demo 中覆盖的四种方法。

1.5 HttpDataType —— 响应数据类型

HttpDataType 枚举控制 HttpResponse.result 的类型:

枚举值数值result 类型适用场景
STRING0stringJSON API 响应、HTML、纯文本
ARRAY_BUFFER1ArrayBuffer二进制数据(图片、文件下载)
OBJECT2Object框架自动 JSON.parse 后的对象

大多数 API 调用场景使用 STRING 类型,这样可以直接拿到 JSON 字符串后用 JSON.parse() 解析。

1.6 HttpResponse —— 响应对象

HttpResponse 包含了完整的响应信息:

interface HttpResponse {
  result: string | ArrayBuffer | Object;  // 响应体
  responseCode: number;                   // HTTP 状态码(200, 404, 500 等)
  header: Object;                         // 响应头键值对
  cookies: string;                        // Cookie 字符串
}

处理响应时的常用模式:

httpReq.request(url, options).then((resp: http.HttpResponse) => {
  if (resp.responseCode >= 200 && resp.responseCode < 300) {
    // 2xx 成功
    const data = JSON.parse(resp.result as string);
  } else if (resp.responseCode === 404) {
    // 资源不存在
  } else {
    // 其他状态码
  }
});

二、核心 API 详解

2.1 createHttp() —— 创建请求实例

function createHttp(): HttpRequest;

createHttp() 是工厂方法,每次调用返回一个新的 HttpRequest 实例。每个实例独立管理自己的连接和超时配置。不能重复使用已经 destroy() 的实例。

2.2 request() —— 发起请求

function request(url: string, options?: HttpRequestOptions): Promise<HttpResponse>;

request() 是异步操作,返回 Promise。请求配置通过 options 参数传入:

  • method:默认 GET,可选 POSTPUTDELETE
  • header:自定义请求头。Content-Type 是最常用的,JSON 请求设为 application/json
  • extraData:请求体,仅 POST/PUT 等带 Body 的方法使用。接受 stringArrayBuffer 类型。在 ArkTS 严格模式下,普通 JS 对象必须先用 JSON.stringify() 转为字符串
  • connectTimeout:TCP 连接超时,单位毫秒,默认 60000
  • readTimeout:数据读取超时,单位毫秒,默认 60000

注意:ArkTS 严格模式下,extraData 接受 stringArrayBuffer 类型,不能直接传递普通对象。发送 JSON 数据时需要先 JSON.stringify()

// 正确:先序列化
options.extraData = JSON.stringify({ title: 'foo', body: 'bar', userId: 1 });

// 错误:ArkTS 严格模式下类型不兼容
options.extraData = { title: 'foo', body: 'bar', userId: 1 };  // 编译错误

2.3 destroy() —— 销毁实例

function destroy(): void;

每个 HttpRequest 实例在使用完毕后必须调用 destroy() 释放连接和内存资源。这是一个同步方法,不会抛异常。最佳实践是在 Promise 的 thencatch 分支中都调用 destroy(),或者在 finally 中统一处理:

httpReq.request(url, options).then((resp) => {
  // 处理响应
  httpReq.destroy();
}).catch((e) => {
  // 处理错误
  httpReq.destroy();
});

在这里插入图片描述
在这里插入图片描述

三、权限配置

使用 @ohos.net.http 需要声明 ohos.permission.INTERNET 权限。这是一项 normal 级别权限,声明即授权,无需用户手动确认。

module.json5 中配置:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

注意:如果使用 HTTPS 双向认证,还需要配置 ohos.permission.INTERNET 外加客户端证书;如果使用了代理功能,可能需要额外网络权限。

四、实战 Demo:网络请求实验室

本节构建一个完整的网络请求调试工具,在一个页面中覆盖 GET/POST/PUT/DELETE 请求构建、响应查看和请求历史追踪。

4.1 页面设计

页面分为五个功能区域:

  1. 快捷请求:三个预设按钮(GET /posts/1、POST /posts、PUT /posts/1),点击即发,方便快速体验不同 HTTP 方法
  2. 请求构建器:方法选择器(GET/POST/PUT/DELETE)+ URL 输入框 + 条件显示的请求体编辑器(仅 POST/PUT 时显示)+ 发送按钮
  3. 响应结果面板:状态码显示(2xx 绿色 / 4xx+ 红色)+ 滚动响应体展示
  4. 请求历史:展示最近 20 条请求记录,含方法标签、URL、时间戳、耗时、状态码
  5. 操作日志:记录所有操作的实时日志流,区分系统信息、成功和错误

4.2 核心实现

发送请求 —— 核心逻辑封装在 sendRequest() 方法中:

private sendRequest(): void {
  if (this.urlInput.trim() === '') {
    this.addLog('请输入 URL', 'error');
    return;
  }
  const method = this.methods[this.methodIndex];
  this.loading = true;
  const startTime = Date.now();
  const httpReq = http.createHttp();
  const options: http.HttpRequestOptions = {
    method: method as http.RequestMethod,
    header: { 'Content-Type': 'application/json' },
    expectDataType: http.HttpDataType.STRING,
    connectTimeout: 10000,
    readTimeout: 10000
  };
  if (method === 'POST' || method === 'PUT') {
    if (this.bodyInput.trim() !== '') {
      options.extraData = this.bodyInput;
    } else {
      options.extraData = JSON.stringify({ title: 'test', body: 'hello', userId: 1 });
    }
  }

  httpReq.request(this.urlInput, options).then((resp: http.HttpResponse) => {
    const elapsed = Date.now() - startTime;
    this.loading = false;
    this.statusCode = resp.responseCode.toString();
    this.statusColor = resp.responseCode >= 200 && resp.responseCode < 300 ?
      '#10B981' : '#EF4444';
    let body = '';
    if (typeof resp.result === 'string') {
      body = resp.result;
    } else if (resp.result instanceof ArrayBuffer) {
      body = '[ArrayBuffer ' + resp.result.byteLength + ' bytes]';
    } else {
      body = '[Object]';
    }
    if (body.length > 2000) {
      body = body.substring(0, 2000) + '\n... (截断)';
    }
    this.responseBody = body;
    // 记录历史
    this.addToHistory(method, elapsed, resp.responseCode);
    this.addLog(method + ' ' + this.urlInput + ' → ' + resp.responseCode +
      ' (' + elapsed + 'ms)', 'success');
    httpReq.destroy();
  }).catch((e: Error) => {
    this.loading = false;
    this.statusCode = '错误';
    this.statusColor = '#EF4444';
    this.responseBody = '请求失败: ' + e.message;
    this.addLog(method + ' 失败: ' + e.message, 'error');
    httpReq.destroy();
  });
}

关键设计点:

  • 使用 Date.now() 计算请求耗时,对性能分析很有价值
  • 响应体超过 2000 字符时截断,避免 UI 渲染性能问题
  • ArrayBufferObject 类型做兼容处理
  • 无论成功还是失败都调用 destroy()

响应体类型处理 —— HttpResponse.result 的类型取决于 expectDataType 配置:

let body = '';
if (typeof resp.result === 'string') {
  body = resp.result;                    // STRING 类型
} else if (resp.result instanceof ArrayBuffer) {
  body = '[ArrayBuffer ' + resp.result.byteLength + ' bytes]';  // ARRAY_BUFFER
} else {
  body = '[Object]';                     // OBJECT 类型
}

快捷演示 —— 预设请求一键发送:

private sendDemo(code: number): void {
  if (code === 1) {
    this.urlInput = 'https://jsonplaceholder.typicode.com/posts/1';
    this.methodIndex = 0;  // GET
    this.bodyInput = '';
    this.sendRequest();
  } else if (code === 2) {
    this.urlInput = 'https://jsonplaceholder.typicode.com/posts';
    this.methodIndex = 1;  // POST
    this.bodyInput = JSON.stringify({ title: 'foo', body: 'bar', userId: 1 });
    this.sendRequest();
  } else if (code === 3) {
    this.urlInput = 'https://jsonplaceholder.typicode.com/posts/1';
    this.methodIndex = 2;  // PUT
    this.bodyInput = JSON.stringify({ id: 1, title: 'updated', body: 'updated', userId: 1 });
    this.sendRequest();
  }
}

这里使用了 jsonplaceholder.typicode.com 这个公开的 REST API 测试服务,它提供标准的 JSON 响应,非常适合开发调试。

4.3 Demo 测试接口说明

Demo 使用的 JSONPlaceholder 接口:

方法端点说明预期响应
GET/posts/1获取单篇文章200,返回文章 JSON
POST/posts创建新文章201,返回创建后的文章(含 id: 101)
PUT/posts/1更新文章200,返回更新后的文章

这些接口是只读模拟(POST/PUT 不会真正修改数据),但返回的 HTTP 状态码和 JSON 结构与真实 API 完全一致,适合开发测试。

4.4 交互方式

Demo 提供四个核心交互点:

  1. 快捷请求按钮:免配置,点击即发送预设的 GET/POST/PUT 请求,适合快速体验不同 HTTP 方法的行为差异
  2. 请求构建器:允许自定义 URL、选择 HTTP 方法、编辑 JSON 请求体(POST/PUT 时显示),完整模拟 API 调试工作流
  3. 响应面板:实时显示 HTTP 状态码(颜色编码:2xx 绿色、4xx+ 红色)和响应体,支持长文本滚动查看
  4. 请求历史:自动记录最近 20 条请求,每条显示方法标签(彩色区分)、URL、时间戳、耗时和状态码,便于对比分析

五、错误处理策略

5.1 常见错误码

@ohos.net.httprequest() 在失败时通过 Promise reject 返回错误,常见错误包括:

场景错误信息排查方向
URL 格式错误Parameter error检查 URL 是否以 http:// 或 https:// 开头
连接超时Connect timeout检查网络连接和 connectTimeout 设置
读取超时Read timeout服务端响应过慢,调大 readTimeout
DNS 解析失败Cannot resolve host检查域名是否正确,DNS 是否可用
SSL 证书错误SSL handshake failed检查 HTTPS 证书是否有效
无网络权限Permission denied检查 module.json5 中的 INTERNET 权限配置
实例已销毁Instance destroyed不能再使用已调用 destroy() 的实例

5.2 超时配置建议

// 不同场景的超时配置建议
const fastOptions: http.HttpRequestOptions = {
  connectTimeout: 5000,   // 快速失败,适合健康检查
  readTimeout: 5000
};

const normalOptions: http.HttpRequestOptions = {
  connectTimeout: 10000,  // 标准 API 调用
  readTimeout: 15000
};

const uploadOptions: http.HttpRequestOptions = {
  connectTimeout: 30000,  // 大文件上传 / 下载
  readTimeout: 60000
};

六、ArkTS 严格模式注意事项

6.1 跨模块类型转换

在 ArkTS 严格模式下,http.RequestMethod 是枚举类型,直接赋值给 options.method 没有问题。但如果 method 来自字符串变量(如 Demo 中的 this.methods[this.methodIndex]),需要使用 as http.RequestMethod 进行类型断言。

6.2 extraData 类型限制

ArkTS 严格模式下,extraData 只接受 stringArrayBuffer,不能传入普通 JS 对象。发送 JSON 时必须用 JSON.stringify() 转换:

// 正确
options.extraData = JSON.stringify({ name: 'test' });

// 编译错误
options.extraData = { name: 'test' };

6.3 result 类型检查

由于 HttpResponse.result 是联合类型(string | ArrayBuffer | Object),使用前需要类型判断。不要假设它一定是 string

if (typeof resp.result === 'string') {
  const text = resp.result;  // 安全
} else if (resp.result instanceof ArrayBuffer) {
  const bytes = resp.result.byteLength;  // ArrayBuffer 特有属性
}

七、实际应用场景

7.1 REST API 调用封装

class ApiClient {
  private baseUrl: string = 'https://api.example.com';

  get<T>(path: string): Promise<T> {
    return this.request<T>(http.RequestMethod.GET, path);
  }

  post<T>(path: string, data: Object): Promise<T> {
    return this.request<T>(http.RequestMethod.POST, path, data);
  }

  private request<T>(method: http.RequestMethod, path: string, data?: Object): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      const httpReq = http.createHttp();
      const options: http.HttpRequestOptions = {
        method: method,
        header: { 'Content-Type': 'application/json' },
        expectDataType: http.HttpDataType.STRING,
        connectTimeout: 10000,
        readTimeout: 10000
      };
      if (data) {
        options.extraData = JSON.stringify(data);
      }
      httpReq.request(this.baseUrl + path, options).then((resp) => {
        httpReq.destroy();
        if (resp.responseCode >= 200 && resp.responseCode < 300) {
          resolve(JSON.parse(resp.result as string) as T);
        } else {
          reject(new Error('HTTP ' + resp.responseCode));
        }
      }).catch((e) => {
        httpReq.destroy();
        reject(e);
      });
    });
  }
}

7.2 文件下载

private downloadFile(url: string): Promise<ArrayBuffer> {
  const httpReq = http.createHttp();
  return httpReq.request(url, {
    method: http.RequestMethod.GET,
    expectDataType: http.HttpDataType.ARRAY_BUFFER,
    readTimeout: 60000
  }).then((resp) => {
    httpReq.destroy();
    return resp.result as ArrayBuffer;
  }).catch((e) => {
    httpReq.destroy();
    throw e;
  });
}

7.3 监听响应头

const httpReq = http.createHttp();
httpReq.on('headersReceive', (header: Object) => {
  console.log('响应头已接收:', JSON.stringify(header));
});
httpReq.request(url, options).then((resp) => {
  // 处理响应体
  httpReq.destroy();
});

headersReceive 事件在响应头到达时立即触发,早于响应体数据完全接收。这允许你在完整数据到达前就获取 Content-Type、Content-Length 等信息,对于大文件下载时的进度提示非常有用。

八、总结

@ohos.net.http 是 HarmonyOS NEXT 中进行 HTTP 网络请求的标准模块。通过本文的学习,你应该已经掌握:

  1. 三步模式createHttp() 创建实例 → request(url, options) 发请求 → destroy() 销毁实例,资源管理清晰明确
  2. 请求配置HttpRequestOptions 包含 method、header、extraData、expectDataType、connectTimeout、readTimeout 等完整配置项
  3. 请求方法RequestMethod 枚举支持 GET/POST/PUT/DELETE 等 9 种 HTTP 方法,覆盖 RESTful API 全部需求
  4. 数据类型HttpDataType 三选一(STRING/ARRAY_BUFFER/OBJECT),控制响应体 result 的类型
  5. 权限配置:需 ohos.permission.INTERNET 权限(normal 级别,声明即授权)
  6. ArkTS 限制:extraData 只能传 string 或 ArrayBuffer,普通对象需 JSON.stringify() 转换

@ohos.net.http 的最佳使用模式可以总结为:

每个请求一个实例,Promise 异步处理,finally 中销毁,合理配置超时。

网络请求是应用与服务端交互的基础设施。优秀的 HTTP 客户端封装应当透明地处理超时重试、错误降级、日志追踪和资源释放。@ohos.net.http 提供了底层的 HTTP 能力,在此之上你可以构建适合自己业务的网络层抽象——无论是简单的 API 调用还是复杂的文件上传下载。

@ohos.net.http 属于 @kit.NetworkKit,与 Android 的 HttpURLConnection / OkHttp 和 iOS 的 URLSession 定位一致。它的 API 体积小巧但功能完整:9 种 HTTP 方法、3 种响应类型、完整的超时控制、代理支持、HTTPS 双向认证——对于绝大多数移动应用场景来说已经足够。

Logo

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

更多推荐