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

一、引言

网络请求是现代应用开发的核心能力。无论是登录认证、数据拉取、文件上传,还是与云端服务交互,都离不开 HTTP 协议。HarmonyOS NEXT 提供了功能强大的 @ohos.net.http 模块(通过 @kit.NetworkKit 访问),支持 GET、POST、PUT、DELETE 等多种请求方法,以及超时控制、请求头定制、响应解析等完整能力。

本文将以一个科技蓝渐变风格的网络请求演示页面为主线,从零开始讲解 HarmonyOS HTTP 客户端的完整使用流程。全文包含大量代码示例和逐行说明,帮助读者彻底掌握网络请求技术。

二、HTTP 协议基础

2.1 HTTP 请求与响应模型

HTTP(超文本传输协议)采用"请求-响应"模型:

  1. 客户端发起请求:客户端(如 HarmonyOS 应用)向服务器发送 HTTP 请求。
  2. 服务器处理请求:服务器根据请求内容进行业务处理。
  3. 服务器返回响应:服务器将处理结果以 HTTP 响应返回给客户端。
  4. 客户端解析响应:客户端解析响应内容并展示给用户。

2.2 HTTP 请求的组成

一个完整的 HTTP 请求由以下部分组成:

组成说明示例
请求行请求方法 + URL + 协议版本GET /get HTTP/1.1
请求头键值对形式的元信息Content-Type: application/json
请求体携带的业务数据{“name”: “AtomCode”}

2.3 HTTP 响应状态码

HTTP 响应状态码由三位数字组成,表示请求的处理结果。常见状态码分类如下:

状态码含义说明
200OK请求成功
301Moved Permanently永久重定向
302Found临时重定向
400Bad Request请求参数错误
401Unauthorized未授权访问
403Forbidden禁止访问
404Not Found资源不存在
500Internal Server Error服务器内部错误
502Bad Gateway网关错误
503Service Unavailable服务不可用

三、HarmonyOS HTTP 模块概览

3.1 模块导入

import { http } from '@kit.NetworkKit';

代码说明:

@kit.NetworkKit 是 HarmonyOS 网络能力套件,http 是其子模块,提供了 HTTP 客户端的全部能力。

3.2 核心类与方法

HarmonyOS HTTP 模块的核心 API 如下:

API说明
http.createHttp()创建 HTTP 请求对象
httpRequest.request()发起网络请求
httpRequest.destroy()销毁请求对象,释放资源
http.RequestMethod请求方法枚举(GET/POST/PUT/DELETE 等)
http.ResponseCode响应状态码枚举

四、实战代码:完整的网络请求页面

下面我们实现一个功能完整的网络请求演示页面,支持 GET 和 POST 两种请求方式,并展示响应结果和状态码速查表。

4.1 定义数据结构

interface StatusRow {
  code: string;
  meaning: string;
  color: string;
}

代码说明:

StatusRow 接口描述状态码表格中的一行数据:

  • code:HTTP 状态码,如 “200”、“404”。
  • meaning:状态码含义说明。
  • color:该状态码对应的展示颜色,用于视觉区分成功、警告、错误等不同类别。

4.2 组件状态定义

@Entry
@Component
struct HttpPage {
  @State statusRows: StatusRow[] = [
    { code: '200', meaning: 'OK 请求成功', color: '#2ED573' },
    { code: '301', meaning: '永久重定向', color: '#FFA502' },
    { code: '400', meaning: '请求参数错误', color: '#FF6348' },
    { code: '401', meaning: '未授权访问', color: '#FF4757' },
    { code: '404', meaning: '资源不存在', color: '#FF4757' },
    { code: '500', meaning: '服务器内部错误', color: '#FF6B81' }
  ];
  @State result: string = '点击下方按钮发起请求';
  @State loading: boolean = false;

代码说明:

  • @State statusRows:状态码表格数据,使用 @State 装饰以便 UI 响应式更新。
  • @State result:请求结果展示文本。
  • @State loading:请求进行中的标志,用于控制按钮文字和防止重复请求。

4.3 发起 GET 请求

async doGet(): Promise<void> {
  this.loading = true;
  this.result = '请求中...';
  const httpRequest = http.createHttp();
  try {
    const resp = await httpRequest.request('https://httpbin.org/get', {
      method: http.RequestMethod.GET,
      connectTimeout: 10000,
      readTimeout: 10000
    });
    if (resp.responseCode === 200) {
      this.result = `状态码: ${resp.responseCode}\n${JSON.stringify(resp.result)}`;
    } else {
      this.result = `状态码: ${resp.responseCode}`;
    }
  } catch (e) {
    this.result = `请求失败: ${JSON.stringify(e)}`;
  } finally {
    httpRequest.destroy();
    this.loading = false;
  }
}

代码说明:

doGet 方法演示了完整的 GET 请求流程:

  1. 设置加载状态this.loading = true 标记请求开始,UI 上的按钮会显示"请求中…"。

  2. 创建请求对象http.createHttp() 创建 HTTP 请求对象。每个请求都应该创建独立的请求对象,避免状态污染。

  3. 发起请求httpRequest.request(url, options) 是核心方法,参数说明如下:

    • 第一个参数:请求的 URL 地址。这里使用 https://httpbin.org/get,httpbin 是一个免费的 HTTP 测试服务,会原样返回请求信息。
    • 第二个参数是请求配置对象:
      • method:请求方法,这里指定为 http.RequestMethod.GET
      • connectTimeout:连接超时时间(毫秒),超过该时间未建立连接则报错。
      • readTimeout:读取超时时间(毫秒),超过该时间未收到数据则报错。
  4. 处理响应

    • resp.responseCode:响应状态码,200 表示成功。
    • resp.result:响应内容,可能是 JSON 字符串、文本或 ArrayBuffer。
    • 成功时用 JSON.stringify 将响应对象格式化为可读文本。
  5. 异常处理catch 块捕获网络异常(如超时、断网、DNS 解析失败),将错误信息展示给用户。

  6. 资源释放finally 块中调用 httpRequest.destroy() 销毁请求对象,释放网络资源。这是非常重要的,如果不销毁会导致资源泄漏。

  7. 恢复状态this.loading = false 标记请求结束。

4.4 发起 POST 请求

async doPost(): Promise<void> {
  this.loading = true;
  this.result = 'POST 请求中...';
  const httpRequest = http.createHttp();
  try {
    const resp = await httpRequest.request('https://httpbin.org/post', {
      method: http.RequestMethod.POST,
      header: { 'Content-Type': 'application/json' },
      extraData: JSON.stringify({ name: 'AtomCode', topic: 'HarmonyOS' }),
      connectTimeout: 10000,
      readTimeout: 10000
    });
    this.result = `状态码: ${resp.responseCode}\n${JSON.stringify(resp.result)}`;
  } catch (e) {
    this.result = `请求失败: ${JSON.stringify(e)}`;
  } finally {
    httpRequest.destroy();
    this.loading = false;
  }
}

代码说明:

doPost 方法与 GET 的关键区别在于请求配置:

  1. 请求方法method: http.RequestMethod.POST 指定使用 POST 方法。

  2. 请求头定制header: { 'Content-Type': 'application/json' } 设置请求头,告诉服务器请求体是 JSON 格式。服务器会根据 Content-Type 正确解析请求体。

  3. 请求体数据extraData 指定请求体内容。这里我们将一个对象序列化为 JSON 字符串。注意:extraData 的类型取决于 Content-Type:

    • 如果是 application/json,需要传入 JSON 字符串。
    • 如果是 application/x-www-form-urlencoded,需要传入表单格式的字符串(如 key1=value1&key2=value2)。

4.5 构建 UI

build() {
  Scroll() {
    Column({ space: 16 }) {
      // 顶部渐变区
      Column() {
        Text('HTTP')
          .fontSize(12)
          .fontColor('#B3E5FC')
          .letterSpacing(8)
        Text('网络请求')
          .fontSize(26)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .margin({ top: 6 })
        Text('http 模块 · GET / POST 实战')
          .fontSize(12)
          .fontColor('#B3E5FC')
          .margin({ top: 6 })
      }
      .width('100%')
      .padding({ top: 48, bottom: 32 })
      .linearGradient({
        angle: 135,
        colors: [['#0F2027', 0], ['#203A43', 0.5], ['#2C5364', 1]]
      })

代码说明:

顶部标题区使用 .linearGradient 设置线性渐变背景,形成科技蓝的视觉效果:

  • angle: 135:渐变方向角度,135 度表示从左上到右下。
  • colors:渐变颜色数组,每个元素是 [颜色, 位置] 的元组,位置取值范围 0 到 1。
  • 这里使用三个颜色节点,形成从深黑蓝到青蓝的渐变过渡。
      // 横向卡片区(Row 布局)
      Row({ space: 12 }) {
        Column({ space: 8 }) {
          Text('GET')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#00D2FF')
          Text('拉取数据\nhttpbin.org/get')
            .fontSize(11)
            .fontColor('#AAAAAA')
            .textAlign(TextAlign.Center)
        }
        .layoutWeight(1)
        .padding(16)
        .backgroundColor('#1A2A3A')
        .borderRadius(16)
        .border({ width: 1, color: '#00D2FF55' })

        Column({ space: 8 }) {
          Text('POST')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor('#FF6B81')
          Text('提交数据\nhttpbin.org/post')
            .fontSize(11)
            .fontColor('#AAAAAA')
            .textAlign(TextAlign.Center)
        }
        .layoutWeight(1)
        .padding(16)
        .backgroundColor('#1A2A3A')
        .borderRadius(16)
        .border({ width: 1, color: '#FF6B8155' })
      }
      .width('100%')

代码说明:

横向卡片区使用 Row 水平布局,展示 GET 和 POST 两种请求方式的说明卡片:

  • 每个卡片是一个 Column,包含方法名和说明文字。
  • .layoutWeight(1) 让两个卡片平分宽度。
  • 卡片背景 #1A2A3A 是深蓝灰色,与整体科技蓝风格统一。
  • .border 设置 1 像素的彩色描边,GET 用青色(#00D2FF),POST 用粉色(#FF6B81),通过颜色区分请求类型。
      // 渐变按钮
      Button(this.loading ? '请求中...' : '发起 GET 请求')
        .width('100%')
        .height(48)
        .fontSize(15)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .linearGradient({
          angle: 90,
          colors: [['#00D2FF', 0], ['#3A7BD5', 1]]
        })
        .borderRadius(24)
        .shadow({ radius: 12, color: '#5500D2FF', offsetY: 4 })
        .onClick(() => { this.doGet(); })

代码说明:

请求按钮采用渐变填充风格:

  • Button(this.loading ? '请求中...' : '发起 GET 请求'):根据 loading 状态动态显示按钮文字,请求中显示"请求中…",防止用户重复点击。
  • .linearGradient:按钮背景使用青蓝渐变,与整体风格一致。
  • .borderRadius(24):设置大圆角,形成胶囊按钮。
  • .shadow:设置按钮阴影,radius 是阴影模糊半径,color 是阴影颜色(带透明度),offsetY 是垂直偏移。阴影让按钮有悬浮感。
      // 结果展示框
      Column() {
        Text('响应结果')
          .fontSize(12)
          .fontColor('#00D2FF')
          .alignSelf(ItemAlign.Start)
        Text(this.result)
          .fontSize(12)
          .fontColor('#E0E0E0')
          .fontFamily('monospace')
          .margin({ top: 8 })
          .alignSelf(ItemAlign.Start)
      }
      .width('100%')
      .padding(16)
      .backgroundColor('#0D1B2A')
      .borderRadius(12)
      .border({ width: 1, color: '#1B3A5C' })

代码说明:

结果展示框用于显示请求响应:

  • 背景色 #0D1B2A 是深蓝黑色,模拟终端效果。
  • .fontFamily('monospace') 使用等宽字体显示响应内容,增强代码感。
  • .alignSelf(ItemAlign.Start) 让内容左对齐。
      // 状态码表格:带彩色标签
      Column() {
        Text('HTTP 状态码速查表')
          .fontSize(14)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .alignSelf(ItemAlign.Start)
          .margin({ bottom: 8 })
        ForEach(this.statusRows, (row: StatusRow) => {
          Row({ space: 10 }) {
            Text(row.code)
              .fontSize(13)
              .fontWeight(FontWeight.Bold)
              .fontColor(row.color)
              .width(56)
              .textAlign(TextAlign.Center)
              .padding({ top: 3, bottom: 3 })
              .borderRadius(4)
              .backgroundColor(`${row.color}22`)
            Text(row.meaning)
              .fontSize(13)
              .fontColor('#CCCCCC')
              .layoutWeight(1)
          }
          .width('100%')
          .padding({ top: 10, bottom: 10 })
          .border({ width: { bottom: 1 }, color: '#1B3A5C' })
        })
      }
      .width('100%')
      .padding(16)
      .backgroundColor('#12263A')
      .borderRadius(12)

代码说明:

状态码速查表是页面的核心表格:

  • 每行包含状态码和含义说明。
  • 状态码使用彩色标签展示:文字颜色为 row.color,背景为 ${row.color}22(在颜色后追加 “22” 表示 22% 透明度的十六进制颜色,这是 HarmonyOS 支持的颜色透明度简写)。
  • 成功状态码(200)为绿色,警告(301)为橙色,错误(400+)为红色,通过颜色直观区分。
  • 行与行之间用底部边框分隔,形成表格效果。

五、HTTP 请求完整配置详解

5.1 请求配置对象

request 方法的第二个参数是完整的请求配置,包含以下可选字段:

const options: http.HttpRequestOptions = {
  method: http.RequestMethod.GET,          // 请求方法
  header: {                                // 请求头
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token123'
  },
  extraData: '请求体数据',                  // 请求体
  expectDataType: http.HttpDataType.STRING, // 期望响应类型
  usingCache: true,                        // 是否使用缓存
  priority: 1,                             // 请求优先级
  connectTimeout: 60000,                   // 连接超时(毫秒)
  readTimeout: 60000,                      // 读取超时(毫秒)
  usingProtocol: http.HttpProtocol.HTTP1_1, // 协议版本
};

代码说明:

  • expectDataType:期望的响应数据类型,可选值包括 STRING(字符串)、OBJECT(JSON 对象)、ARRAY_BUFFER(二进制数据)。设置正确的类型可以避免手动解析。
  • usingCache:是否启用缓存,启用后相同请求会优先使用缓存。
  • usingProtocol:HTTP 协议版本,默认 HTTP1_1,也可指定 HTTP2。

5.2 支持的所有请求方法

http.RequestMethod.OPTIONS   // 查询服务器支持的方法
http.RequestMethod.GET       // 获取资源
http.RequestMethod.HEAD      // 获取响应头(无响应体)
http.RequestMethod.POST      // 提交数据
http.RequestMethod.PUT       // 更新资源
http.RequestMethod.DELETE    // 删除资源
http.RequestMethod.TRACE     // 回显请求(诊断用)
http.RequestMethod.CONNECT   // 建立隧道连接

5.3 响应对象详解

const resp = await httpRequest.request(url, options);

// 响应状态码
const code = resp.responseCode;

// 响应头
const headers = resp.header;

// 响应数据(类型由 expectDataType 决定)
const data = resp.result;

// 原始响应数据(ArrayBuffer)
const raw = resp.result as ArrayBuffer;

// 响应内容类型
const contentType = resp.header['Content-Type'];

六、常见请求场景实战

6.1 携带 Token 的认证请求

async function fetchUserInfo(token: string): Promise<string> {
  const httpRequest = http.createHttp();
  try {
    const resp = await httpRequest.request('https://api.example.com/user', {
      method: http.RequestMethod.GET,
      header: {
        'Authorization': `Bearer ${token}`,
        'Accept': 'application/json'
      },
      expectDataType: http.HttpDataType.OBJECT
    });
    if (resp.responseCode === 200) {
      return JSON.stringify(resp.result);
    }
    return `请求失败: ${resp.responseCode}`;
  } finally {
    httpRequest.destroy();
  }
}

6.2 表单提交

const httpRequest = http.createHttp();
const resp = await httpRequest.request('https://api.example.com/login', {
  method: http.RequestMethod.POST,
  header: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  extraData: 'username=admin&password=123456'
});

6.3 下载文件

const httpRequest = http.createHttp();
const resp = await httpRequest.request('https://example.com/file.zip', {
  method: http.RequestMethod.GET,
  expectDataType: http.HttpDataType.ARRAY_BUFFER
});
const buffer = resp.result as ArrayBuffer;
// 将 ArrayBuffer 写入文件(需要 fileIo 配合)

七、网络权限配置

在 HarmonyOS 中发起网络请求需要申请网络权限。在 module.json5 中添加:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

代码说明:

  • ohos.permission.INTERNET:网络访问权限,是发起 HTTP 请求的必需权限。
  • 如果应用需要访问网络状态,还需要申请 ohos.permission.GET_NETWORK_INFO 权限。

八、最佳实践

8.1 统一封装请求工具

在实际项目中,建议将 HTTP 请求封装为统一工具类,便于管理和复用:

export class HttpUtil {
  static async get<T>(url: string): Promise<T> {
    const httpRequest = http.createHttp();
    try {
      const resp = await httpRequest.request(url, {
        method: http.RequestMethod.GET,
        expectDataType: http.HttpDataType.OBJECT
      });
      return resp.result as T;
    } finally {
      httpRequest.destroy();
    }
  }
}

8.2 超时处理

务必设置合理的超时时间,避免请求长时间挂起:

const resp = await httpRequest.request(url, {
  connectTimeout: 10000,  // 10 秒连接超时
  readTimeout: 30000      // 30 秒读取超时
});

8.3 资源释放

每次请求完成后务必调用 destroy() 释放资源,推荐使用 try...finally 结构。

8.4 错误处理

网络请求可能失败的原因很多:断网、超时、DNS 解析失败、服务器错误等。建议对错误进行分类处理,给用户友好的提示。

九、常见问题

9.1 请求报错"no permission"

原因:没有在 module.json5 中配置 ohos.permission.INTERNET 权限。

解决:添加网络权限配置。

9.2 HTTPS 证书校验失败

原因:服务器证书不受信任。

解决:检查服务器证书是否有效;开发阶段可临时关闭证书校验(不推荐生产环境使用)。

9.3 请求结果类型不正确

原因:没有设置 expectDataType,或响应内容与期望类型不匹配。

解决:根据实际响应内容设置正确的 expectDataType

十、总结

本文完整讲解了 HarmonyOS HTTP 网络请求的开发流程。我们实现了一个科技蓝渐变风格的网络请求演示页面,支持 GET 和 POST 两种请求方式,并详细解析了请求配置、响应处理、错误处理等核心知识点。

核心要点回顾:

  1. 使用 http.createHttp() 创建请求对象,请求完成后必须 destroy() 释放资源。
  2. 通过 request() 方法的配置对象设置方法、请求头、请求体、超时等参数。
  3. 根据响应状态码判断请求结果,200 表示成功。
  4. 设置 expectDataType 可以自动解析响应数据。
  5. 需要配置 ohos.permission.INTERNET 网络权限。
  6. 建议封装统一的请求工具类,实现代码复用。

网络请求是连接应用与云端的桥梁,掌握它之后,我们就可以构建真正具有云端能力的应用了。下一篇我们将深入讲解 HarmonyOS 状态管理机制。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐