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

一、引言

网络请求是现代应用开发的核心能力。无论是登录认证、数据拉取、文件上传,还是与云端服务交互,都离不开 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 响应状态码由三位数字组成,表示请求的处理结果。常见状态码分类如下:

状态码 含义 说明
200 OK 请求成功
301 Moved Permanently 永久重定向
302 Found 临时重定向
400 Bad Request 请求参数错误
401 Unauthorized 未授权访问
403 Forbidden 禁止访问
404 Not Found 资源不存在
500 Internal Server Error 服务器内部错误
502 Bad Gateway 网关错误
503 Service 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、测试、元服务和应用上架分发等。

更多推荐