杨利杰YJlio博客头图

网络请求与JSON解析

大家好,我是杨利杰 YJlio。

上一节整理了Promise与async/await。这一节我把等待逻辑接到网络请求上:先配置权限和接口,再检查HTTP响应,解析JSON,最后把校验后的message交给页面。

本篇编号030,计划日期2026年10月20日。原稿已保留。本文代码尚未经过SDK编译或设备实测,图片均为概念示意;不把示例当成已完成的联网实验。

一、先分清模拟结果与真实请求

原稿用Promise.resolve返回一个带message的对象,适合练习页面赋值,但它没有发送HTTP请求,也没有解析服务端JSON文本。

本篇改用Network Kit的http接口。完整路径是:配置地址→创建请求→await响应→检查状态和响应体→解析字段→更新状态。任何一步失败,都应进入错误处理。

取得响应、解析成功与业务成功是不同的判断,不能只看到Promise完成就显示成功。

本例约定HTTP状态为200,响应为含string类型message字段的JSON对象。这是练习契约,不代表所有接口都采用同样结构;真实业务还可能有code、data等字段,需要另行校验。

模拟响应不是真实请求

二、配置网络权限和实际接口

在entry/src/main/module.json5的module对象下,合并requestPermissions。下面是局部片段,不要用它覆盖整个配置文件,也不要重复建立同名字段:

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

保留原有权限项。本节不加入与请求无关的权限。

代码中的ENDPOINT默认留空,运行前改成自己的或有授权的HTTPS测试接口。接口应按本篇契约返回JSON对象。这里不填一个可能返回HTML的公共页面来冒充业务接口。

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

const ENDPOINT: string = '';

interface MessagePayload {
  message: string;
}

没有真实环境时,先核对代码和契约;连接、证书与服务端响应仍属于待验证事项。不要为让示例运行而关闭证书验证。

先配置权限与接口地址

三、一次请求创建一个HttpRequest对象

下面函数和后面的parseMessage、页面组件放在同一个Index.ets学习文件中。创建请求后,用finally释放资源:

async function fetchMessage(url: string): Promise<string> {
  if (!url.startsWith('https://')) {
    throw new Error('请先配置授权的HTTPS接口地址');
  }
  const request = http.createHttp();
  try {
    const response = await request.request(url, {
      method: http.RequestMethod.GET,
      expectDataType: http.HttpDataType.STRING,
      connectTimeout: 10000,
      readTimeout: 10000
    });
    if (response.responseCode !== 200) {
      throw new Error(`HTTP状态不符合预期:${response.responseCode}`);
    }
    if (typeof response.result !== 'string') {
      throw new Error('响应体不是字符串');
    }
    return parseMessage(response.result);
  } finally {
    request.destroy();
  }
}

connectTimeout和readTimeout是毫秒配置值,不是实测耗时,也不能相加写成严格的整体任务时限。地址前缀检查只是本例的提示,不是完整的URL合法性或可信性审查。

按官方接口说明,每次请求创建自己的HttpRequest对象,请求结束后调用destroy。这里没有复用已销毁的对象。

一次请求一个对象

四、HTTP状态与响应体分别检查

本例先要求responseCode为200,再检查result确实是string。即使请求Promise返回了响应,也可能拿到不符合本例要求的HTTP状态。

expectDataType指定希望得到字符串,代码仍保留运行时类型检查。不要直接用as string把不匹配的响应强行当作JSON文本。

200也不能保证响应体是合法JSON,更不能代替业务字段校验。接口返回错误页、空文本或另一套JSON结构时,后续处理仍应失败。

HTTP状态与响应体分别检查

五、JSON.parse之后继续验证message

function parseMessage(text: string): string {
  const parsed = JSON.parse(text) as MessagePayload | null;
  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
    throw new Error('JSON顶层必须是对象');
  }
  if (typeof parsed.message !== 'string') {
    throw new Error('JSON缺少string类型的message');
  }
  return parsed.message;
}

JSON.parse遇到非法文本会抛出异常。合法JSON也可能是null、数组、数字或字符串,因此还要检查顶层结构与message类型。

as只帮助编译期描述类型,不会替服务端数据做运行时校验。

这里允许message为空字符串,因为契约只要求string。如果业务要求非空,需要明确增加校验;不能把空字符串和网络异常混为一谈。

JSON解析后还要检查字段

六、页面只显示校验后的文本

下面组件调用fetchMessage。新请求开始时先清空旧文本和旧错误,避免把上一轮结果当成本轮结果:

@Entry
@Component
struct Index {
  @State loading: boolean = false;
  @State message: string = '';
  @State errorMessage: string = '';
  @State completed: boolean = false;

  private async loadData(): Promise<void> {
    if (this.loading) return;
    this.loading = true;
    this.message = '';
    this.errorMessage = '';
    this.completed = false;
    try {
      this.message = await fetchMessage(ENDPOINT);
      this.completed = true;
    } catch (error) {
      const err = error as BusinessError;
      this.errorMessage = String(err.message);
      console.error(`request failed: ${err.code}, ${err.message}`);
    } finally {
      this.loading = false;
    }
  }

  build() {
    Column({ space: 16 }) {
      Text('请求与JSON解析练习')
      Button('加载数据')
        .enabled(!this.loading)
        .onClick(() => {
          this.loadData()
        })
      if (this.loading) {
        Text('处理中')
      }
      if (this.completed) {
        Text(this.message.length === 0 ? 'message为空字符串' : this.message)
      }
      if (this.errorMessage.length > 0) {
        Text(this.errorMessage)
      }
    }
    .width('100%')
    .height('100%')
    .padding(24)
  }
}

completed区分尚未完成与已取得空字符串;它只表示本例请求和字段检查完成,不是通用的业务成功标志。

示例中平台错误可含BusinessError错误码,手动抛出的Error不一定有code。保留完整诊断,但不要向日志写入令牌、Cookie或整段敏感响应。真实服务返回的业务错误结构需单独定义。

页面只接收校验后的结果

七、请求资源与页面状态分两层清理

层次finally中的操作目的
fetchMessagerequest.destroy()释放本次请求资源
loadDataloading=false结束页面加载状态,恢复按钮

请求层只返回校验后的string或抛出错误,页面层负责提示与状态。两层都处理各自的收尾,不能只恢复按钮而忘记请求资源。

finally负责收尾,不会自动重试,也不会自动替页面设计离开后的取消策略。

loading只限制当前组件重复进入。本例没有自动重试、缓存或离开页面时中断请求的实现;接入实际工程时应按接口能力设计,不能把重新点击按钮当作可靠重试机制。

清理请求与恢复界面分两层

八、按失败位置记录实验结果

场景应检查的边界实际结果
ENDPOINT未配置明确提示配置HTTPS地址待验证
权限未声明核对权限配置与完整错误待验证
断网或超时显示错误并结束加载待验证
非200响应不继续当作本例成功结果待验证
非JSON文本解析失败进入错误提示待验证
null、数组或字段类型不符拒绝不符合契约的结构待验证
合法message字符串展示校验后的文本待验证
合法空字符串显示明确的空字符串提示待验证
快速重复点击当前页面不重复发起待验证

记录实际SDK/API、工具和设备版本、请求时的网络环境、HTTP状态及错误信息。没有真实响应与设备日志,不能宣称联网成功、性能改善或兼容某个版本。

记录请求与解析的验证路径

写在最后

这节我把原稿里的模拟赋值改成了完整的请求学习路径:权限和地址准备、请求对象创建、响应检查、JSON结构校验、页面映射和资源清理。

后续学习网络请求加载态与错误态时,可以在这条路径上逐步完善体验。先让页面提示对应实际阶段,再考虑重试与缓存,比较容易定位问题。

参考资料

  1. 华为开发者文档:HTTP数据请求指南。
  2. 华为开发者文档:http接口参考。请求对象、配置和资源释放以实际SDK对应文档为准。
  3. 原稿《发起网络请求并解析JSON》,030/102,计划日期2026-10-20;原稿保留。

声明:本文为个人学习笔记,代码未进行SDK编译、模拟器或设备实测,未验证真实接口返回。配图为概念示意,实际运行记录需在独立练习环境补充。

结束分隔线

返回顶部

Logo

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

更多推荐