Skip to content

HTTP 网络请求

在 HarmonyOS 5.0 中,我们可以使用@ohos.net.http 模块封装基于 Promise 的 HTTP 请求。以下是完整实现方案:

流程图

效果图

添加网络权限

  • module.json5中添加网络权限:
json
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

(1) 创建 Promise 封装工具 (httpUtil.ts)

ts
import http from "@ohos.net.http";
import { BusinessError } from "@ohos.base";

interface ResType {
  code: number;
  msg: string;
  data: object;
}

// 定义请求配置类型
type RequestConfig = {
  url: string;
  method?:
    | http.RequestMethod.GET
    | http.RequestMethod.POST
    | http.RequestMethod.PUT
    | http.RequestMethod.DELETE;
  header?: Object;
  body?: string | Object;
};

// 封装HTTP请求
export function httpRequest(config: RequestConfig): Promise<any> {
  return new Promise((resolve, reject) => {
    // 1. 创建HTTP客户端
    const httpRequest = http.createHttp();

    // 2. 处理请求体(对象转JSON字符串)
    let requestBody = config.body;
    if (typeof config.body === "object") {
      requestBody = JSON.stringify(config.body);
      config.header = {
        ...config.header,
        "Content-Type": "application/json",
      };
    }

    // 3. 发送请求
    httpRequest.request(
      config.url,
      {
        method: config.method || http.RequestMethod.GET,
        header: config.header || {},
        extraData: requestBody,
      },
      (err: BusinessError, response: http.HttpResponse) => {
        // 4. 处理响应
        if (err) {
          httpRequest.destroy(); // 释放资源
          reject(new Error(`Network error: ${err.code} - ${err.message}`));
          return;
        }
        // 5. 检查状态码
        if (response.responseCode >= 200 && response.responseCode < 300) {
          try {
            // 6. 尝试解析JSON
            // 表示成功了 这里只能用String 不能用JSON.stringify
            let res: ResType = response.result as ResType;
            let result = JSON.parse(String(res));
            if (result.code == 200) {
              resolve(result.data);
            } else {
              resolve(result.msg);
            }
          } catch (e) {
            resolve(response.result); // 返回原始数据
          }
        } else {
          reject(new Error(`HTTP ${response.responseCode}: ${response}`));
        }

        // 7. 释放资源
        httpRequest.destroy();
      }
    );
  });
}

// 快捷方法
export const httpGet = async <T>(
  url: string,
  header?: Object
): Promise<ResType> => {
  return await httpRequest({ url, method: http.RequestMethod.GET, header });
};

export const httpPost = async <T>(
  url: string,
  body: Object | string,
  header?: Object
): Promise<ResType> => {
  return await httpRequest({
    url,
    method: http.RequestMethod.POST,
    body,
    header,
  });
};

(2)业务中使用

ts
import { httpGet, httpPost } from "../utils/httpUtils";

interface ResType {
  code: number;
  msg: string;
  data: object;
}

class IndexApi {
  public baseurl: string = "https://newapidev.dianyuan.com";

  // 获取数据
  async getUserData() {
    try {
      const url = "/page/v2025/tek250612/getInfo";
      const result: object = await httpPost(
        this.baseurl + url,
        {},
        {
          "Access-Token": "xxxxxxxx",
          "Client-Type": "web",
          Sign: "xxxxxxx",
        }
      );
      console.log("888999");
      console.log(JSON.stringify(result));
      return result;
    } catch (error) {
      console.log("请求失败" + error.message);
      return `请求失败 + ${error.message}`;
    }
  }
}

const IndexClassApi = new IndexApi();

export default IndexClassApi;
ts

import IndexClassApi from "../api/IndexApi"
import { JSON } from "@kit.ArkTS";
@Entry
@Component
struct Index {
    @State message: string = 'Hello World';

    build() {
        Column() {
            Button("点击").type(ButtonType.Normal).onClick(async () => {
                const result = await IndexClassApi.getUserData()
                console.log("9999")
                console.log(JSON.stringify(result))
            })
        }
    }
}

补充

添加超时控制

ts
// 在request配置中添加
httpRequest.request(config.url, {
  connectTimeout: 30000, // 30秒超时
  // ...其他配置
});

添加重试机制

ts
async function requestWithRetry(config: RequestConfig, retries = 3) {
  try {
    return await httpRequest(config);
  } catch (error) {
    if (retries > 0) {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      return requestWithRetry(config, retries - 1);
    }
    throw error;
  }
}

添加请求拦截器

ts
// 全局请求拦截示例
const originalRequest = httpRequest;
httpRequest = async (config) => {
  // 添加全局token
  config.header = {
    ...config.header,
    Authorization: `Bearer ${getGlobalToken()}`,
  };
  return originalRequest(config);
};