技术分享

鸿蒙网络请求:http模块+async/await,从服务器获取数据 | 从零到一第16篇

前面的例子用的都是本地模拟数据。本文讲数据从服务器拉取。鸿蒙的网络请求用 @kit.NetworkKit

 里的 http

 模块,异步处理用 async/await

。学完这篇,列表数据、详情数据换成真实接口。

16.1 http 模块基础:发送 GET 请求

模块导入 @kit.NetworkKit

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

最基础的 GET 请求:

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

const httpRequest = http.createHttp();
const requestOptions: http.HttpRequestOptions = {
  method: http.RequestMethod.GET,
  header: { 'Content-Type': 'application/json' },
  connectTimeout: 15000,
  readTimeout: 15000
};

httpRequest.request(
  'https://api.example.com/articles',
  requestOptions,
  (err, data) => {
    if (!err) {
      console.log('请求成功:' + data.result);
    } else {
      console.error('请求失败:' + err.message);
    }
  }
);

createHttp()

 创建一个 HTTP 客户端实例。request()

 发请求,第一个参数是 URL,第二个是 HttpRequestOptions

 配置对象,第三个是回调。

connectTimeout

 是建立连接的超时时间,readTimeout

 是等待服务器响应的超时时间,单位毫秒。设了超时就不用担心请求卡死。

请求完成销毁实例,释放资源:

httpRequest.destroy();

16.2 请求参数和返回数据,全部对象化

这是本文的重点,所有参数和返回数据都必须用对象。

请求参数:

要带查询参数,不要自己在 URL 后面拼 ?key=value&key2=value2

。用 extraData

 传一个对象,框架自动序列化:

const requestOptions: http.HttpRequestOptions = {
  method: http.RequestMethod.GET,
  extraData: {
    page: 1,
    pageSize: 20,
    category: 'tech'
  },
  connectTimeout: 15000,
  readTimeout: 15000
};

旧写法里 data.result

 返回的是 string,每次都要手动 JSON.parse

expectDataType

 设为 http.HttpDataType.OBJECT

data.result

 是解析好的对象。

const requestOptions: http.HttpRequestOptions = {
  method: http.RequestMethod.GET,
  expectDataType: http.HttpDataType.OBJECT,
  connectTimeout: 15000,
  readTimeout: 15000
};

const response = await httpRequest.request('https://api.example.com/articles', requestOptions);

// 不需要 JSON.parse,直接用
const result = response.result as ApiResponse;
if (result.code === 200) {
  this.articleList = result.data;
}

expectDataType

 支持三种:

16.3 用 async/await 改写

用 async/await

,异步代码读起来跟同步一样:

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

async function fetchArticles(): Promise<Article[]> {
  const httpRequest = http.createHttp();
  try {
    const requestOptions: http.HttpRequestOptions = {
      method: http.RequestMethod.GET,
      expectDataType: http.HttpDataType.OBJECT,
      connectTimeout: 15000,
      readTimeout: 15000
    };
    const response = await httpRequest.request('https://api.example.com/articles', requestOptions);
    const result = response.result as ApiResponse;
    return result.code === 200 ? result.data : [];
  } catch (err) {
    console.error('请求失败:' + JSON.stringify(err));
    return [];
  } finally {
    httpRequest.destroy();
  }
}

await

 等待请求结果,try-catch

 捕获异常,finally

 里销毁实例。

await

 只能放在 async

 函数里。build()

 方法不是 async 函数,网络请求的逻辑要封装成 async 函数,在 aboutToAppear

 或其他生命周期里调用。

16.4 定义数据模型

接口返回什么结构,就用 type

 或 interface

 定义清楚。这是对象化的前提——数据进来到出去,每一步都有类型约束:

// 文章对象
type Article = {
  id: string;
  title: string;
  author: string;
  readCount: number;
};

// 接口返回体
type ApiResponse = {
  code: number;
  data: Article[];
  message?: string;
};

16.5 数据驱动 UI 刷新

解析完的数据赋值给 @State 变量,UI 自动刷新:

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

@Entry
@Component
struct ArticleListPage {
  @State articleList: Article[] = [];
  @State isLoading: boolean = false;

  async aboutToAppear(): Promise<void> {
    await this.loadArticles();
  }

  async loadArticles(): Promise<void> {
    this.isLoading = true;
    const httpRequest = http.createHttp();
    try {
      const requestOptions: http.HttpRequestOptions = {
        method: http.RequestMethod.GET,
        expectDataType: http.HttpDataType.OBJECT,
        extraData: { page: 1, pageSize: 20 },
        connectTimeout: 15000,
        readTimeout: 15000
      };
      const response = await httpRequest.request('https://api.example.com/articles', requestOptions);
      const result = response.result as ApiResponse;
      if (result.code === 200) {
        this.articleList = result.data;  // 赋值,UI 自动刷新
      }
    } catch (err) {
      console.error('加载失败:' + JSON.stringify(err));
    } finally {
      this.isLoading = false;
      httpRequest.destroy();
    }
  }

  build() {
    if (this.isLoading) {
      Column() {
        Text('加载中...')
          .fontSize(16)
          .fontColor('#999999')
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }

    List() {
      ForEach(this.articleList, (item: Article) => {
        ListItem() {
          Column() {
            Text(item.title)
              .fontSize(18)
              .fontWeight(FontWeight.Medium)
            Row() {
              Text(item.author)
                .fontSize(14)
                .fontColor('#666666')
              Text(`${item.readCount}阅读`)
                .fontSize(14)
                .fontColor('#999999')
                .margin({ left: 10 })
            }
            .margin({ top: 8 })
          }
          .padding(16)
          .width('100%')
        }
      })
    }
  }
}

注意:需要网络请求必须在 module.json5

 里声明权限:

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

16.6 常见报错处理

请求没反应也没报错:检查 module.json5

 里有没有声明 INTERNET 权限。没声明权限,请求会失败。

导入报错:检查导入路径是不是 import { http } from '@kit.NetworkKit'

。旧的 @ohos.net.http

 已经废弃。

await

 编译报错:await

 只能放在 async

 函数里。build()

 方法不是 async 函数。

JSON.parse

 报错:如果用 expectDataType: http.HttpDataType.OBJECT

,不用手动 JSON.parse

16.7 本篇总结

常见问题

Q: 新版 http 怎么导入?

A: import { http } from '@kit.NetworkKit'

。旧的 @ohos.net.http

 已废弃。

Q: 请求参数怎么传?

A: GET 参数和 POST 请求体都用 extraData

 传对象,框架自动序列化。

Q: 返回数据怎么直接拿对象?

A: 设置 expectDataType: http.HttpDataType.OBJECT

result

 直接是对象,不用 JSON.parse

Q: 超时怎么设?

A: HttpRequestOptions

 里设 connectTimeout

(连接超时)和 readTimeout

(读取超时),单位毫秒。

Q: 发网络请求需要什么权限?

A: module.json5

 里声明 ohos.permission.INTERNET

重庆华鸿科技 深耕鸿蒙生态人才培养,推出《HarmonyOS 应用开发者认证培训班》《HarmonyOS 应用开发者原生开发精研班》《HarmonyOS 原生应用项目实战与就业班》,由华为官方认证讲师授课,手把手带您从零构建商业级鸿蒙应用。

立即咨询