引言

网络请求是移动应用中最基础也最频繁的操作之一。无论是获取服务端数据、提交表单、上传文件还是调用第三方 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 类型 适用场景
STRING 0 string JSON API 响应、HTML、纯文本
ARRAY_BUFFER 1 ArrayBuffer 二进制数据(图片、文件下载)
OBJECT 2 Object 框架自动 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开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐