前置知识: HarmonyOS

网络请求

00:00
3 min Intermediate 2026/6/14

HTTP请求与数据获取

概述

网络请求是大多数应用的核心能力。HarmonyOS 提供了 @ohos.net.http 模块用于发起 HTTP 请求,支持 GET、POST、PUT、DELETE 等常见方法。此外还有 @ohos.net.webSocket 用于 WebSocket 通信。理解网络请求的用法,是构建与服务器交互的应用的基础。

为什么需要网络请求?现代应用几乎都需要从服务器获取数据或提交数据。新闻应用需要拉取文章列表,电商应用需要获取商品信息,社交应用需要发送消息。掌握网络请求的用法,是应用开发的基本功。

基础概念

HTTP 请求:基于 HTTP 协议的请求-响应模型。客户端发送请求,服务端返回响应。常用的请求方法有 GET(获取数据)、POST(提交数据)、PUT(更新数据)、DELETE(删除数据)。

HttpRequest:HarmonyOS 的 HTTP 请求对象,通过 http.createHttp() 创建。每个请求对象只能使用一次,使用后需要调用 destroy() 销毁

请求:附加在请求中的元数据,如 Content-Type、Authorization 等,用于告诉服务器请求的式和身份信息。

响应服务器返回的数据,状态码、响应头响应体。

快速上手

简单的 GET 请求

import http from '@ohos.net.http'

@Entry
@Component
struct HttpDemo {
  @State result: string = '点击按钮发起请求'

  async fetchData() {
    // 创建 HTTP 请求对象
    const httpRequest = http.createHttp()

    try {
      // 发起 GET 请求
      const response = await httpRequest.request('https://api.example.com/data', {
        method: http.RequestMethod.GET,
        header: { 'Content-Type': 'application/json' }
      })

      // 处理响应
      if (response.responseCode === 200) {
        this.result = response.result as string
      } else {
        this.result = `请求失败: ${response.responseCode}`
      }
    } catch (error) {
      this.result = `请求异常: ${error}`
    } finally {
      // 销毁请求对象
      httpRequest.destroy()
    }
  }

  build() {
    Column() {
      Text(this.result).fontSize(16)
      Button('获取数据').onClick(() => this.fetchData())
    }
    .padding(16)
  }
}

详细用法

POST 请求

import http from '@ohos.net.http';

async function postRequest() {
  const httpRequest = http.createHttp();

  try {
    const response = await httpRequest.request('https://api.example.com/users', {
      method: http.RequestMethod.POST,
      header: {
        'Content-Type': 'application/json', // 指定请求体格式
      },
      extraData: {
        // 请求体数据
        name: '张三',
        email: 'zhang@example.com',
        age: 25,
      },
    });

    console.info(`响应码: ${response.responseCode}`);
    console.info(`响应体: ${response.result}`);
  } finally {
    httpRequest.destroy();
  }
}

带认证的请求

async function authenticatedRequest(token: string) {
  const httpRequest = http.createHttp();

  try {
    const response = await httpRequest.request('https://api.example.com/profile', {
      method: http.RequestMethod.GET,
      header: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`, // 携带认证令牌
      },
    });

    if (response.responseCode === 401) {
      console.warn('令牌已过期,需要重新登录');
    }

    return response;
  } finally {
    httpRequest.destroy();
  }
}

上传文件

async function uploadFile(filePath: string) {
  const httpRequest = http.createHttp();

  try {
    const response = await httpRequest.request('https://api.example.com/upload', {
      method: http.RequestMethod.POST,
      header: {
        'Content-Type': 'multipart/form-data',
      },
      extraData: {
        // 使用文件路径上传
        file: filePath,
      },
    });

    console.info(`上传结果: ${response.responseCode}`);
  } finally {
    httpRequest.destroy();
  }
}

请求超时和重试

async function requestWithRetry(url: string, maxRetries: number = 3) {
  let lastError: Error | null = null;

  for (let i = 0; i < maxRetries; i++) {
    const httpRequest = http.createHttp();

    try {
      const response = await httpRequest.request(url, {
        method: http.RequestMethod.GET,
        header: { 'Content-Type': 'application/json' },
        connectTimeout: 10000, // 连接超时: 10秒
        readTimeout: 30000, // 读取超时: 30秒
      });

      if (response.responseCode === 200) {
        return response.result;
      }

      // 服务器错误,可以重试
      if (response.responseCode >= 500) {
        lastError = new Error(`服务器错误: ${response.responseCode}`);
        continue;
      }

      // 客户端错误,不重试
      throw new Error(`请求失败: ${response.responseCode}`);
    } catch (error) {
      lastError = error as Error;
    } finally {
      httpRequest.destroy();
    }

    // 等待一段时间后重试
    if (i < maxRetries - 1) {
      await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));
    }
  }

  throw lastError;
}

封装网络请求工具

import http from '@ohos.net.http';

// 请求配置
interface RequestConfig {
  url: string;
  method?: http.RequestMethod;
  data?: object;
  header?: object;
  timeout?: number;
}

// 响应结果
interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

// 封装请求方法
class HttpClient {
  private baseUrl: string = 'https://api.example.com';
  private token: string = '';

  // 设置认证令牌
  setToken(token: string) {
    this.token = token;
  }

  // 通用请求方法
  async request<T>(config: RequestConfig): Promise<ApiResponse<T>> {
    const httpRequest = http.createHttp();

    try {
      const header: Record<string, string> = {
        'Content-Type': 'application/json',
        ...(config.header as Record<string, string>),
      };

      // 如果有令牌,添加到请求头
      if (this.token) {
        header['Authorization'] = `Bearer ${this.token}`;
      }

      const response = await httpRequest.request(`${this.baseUrl}${config.url}`, {
        method: config.method || http.RequestMethod.GET,
        header: header,
        extraData: config.data,
        connectTimeout: config.timeout || 10000,
        readTimeout: config.timeout || 30000,
      });

      if (response.responseCode === 200) {
        return JSON.parse(response.result as string) as ApiResponse<T>;
      } else if (response.responseCode === 401) {
        throw new Error('未授权,请重新登录');
      } else {
        throw new Error(`请求失败: ${response.responseCode}`);
      }
    } catch (error) {
      console.error(`请求异常: ${error}`);
      throw error;
    } finally {
      httpRequest.destroy();
    }
  }

  // 便捷方法
  async get<T>(url: string) {
    return this.request<T>({ url, method: http.RequestMethod.GET });
  }

  async post<T>(url: string, data?: object) {
    return this.request<T>({ url, method: http.RequestMethod.POST, data });
  }

  async put<T>(url: string, data?: object) {
    return this.request<T>({ url, method: http.RequestMethod.PUT, data });
  }

  async delete<T>(url: string) {
    return this.request<T>({ url, method: http.RequestMethod.DELETE });
  }
}

// 使用
const client = new HttpClient();

// GET 请求
const users = await client.get<User[]>('/users');

// POST 请求
const newUser = await client.post<User>('/users', {
  name: '张三',
  email: 'zhang@example.com',
});

常见场景

列表数据加载

interface Article {
  id: number
  title: string
  content: string
}

@Entry
@Component
struct ArticleList {
  @State articles: Article[] = []
  @State isLoading: boolean = false
  @State errorMsg: string = ''

  async loadArticles() {
    this.isLoading = true
    this.errorMsg = ''

    try {
      const httpRequest = http.createHttp()
      const response = await httpRequest.request('https://api.example.com/articles', {
        method: http.RequestMethod.GET,
        header: { 'Content-Type': 'application/json' }
      })

      if (response.responseCode === 200) {
        const result = JSON.parse(response.result as string)
        this.articles = result.data as Article[]
      }
      httpRequest.destroy()
    } catch (error) {
      this.errorMsg = '加载失败,请重试'
    } finally {
      this.isLoading = false
    }
  }

  build() {
    Column() {
      if (this.isLoading) {
        LoadingProgress().width(48).height(48)
      } else if (this.errorMsg) {
        Text(this.errorMsg).fontColor(Color.Red)
        Button('重试').onClick(() => this.loadArticles())
      } else {
        List() {
          ForEach(this.articles, (article: Article) => {
            ListItem() {
              Column() {
                Text(article.title).fontSize(18).fontWeight(FontWeight.Bold)
                Text(article.content).fontSize(14).maxLines(2)
              }
              .padding(16)
            }
          })
        }
      }
    }
    .onAppear(() => this.loadArticles())
  }
}

注意事项

网络权限:在 module.json5 中需要声明网络权限"requestPermissions": [{ "name": "ohos.permission.INTERNET" }]

线程安全HTTP 请求是异步操作,不会阻塞主线程。但不要在回调执行耗时操作,应使用 TaskPool 处理

HTTPS生产环境应使用 HTTPS,避免明文传输敏感数据

请求对象复用:每个 HttpRequest 对象只能使用一次,使用后必须调用 destroy() 销毁。不要复用请求对象发起新请求

内存泄漏:在组件销毁时(aboutToDisappear),确保取消完成请求

进阶用法

WebSocket 通信

import webSocket from '@ohos.net.webSocket'

@Component
struct WebSocketDemo {
  @State messages: string[] = []
  private ws: webSocket.WebSocket | null = null

  async connectWebSocket() {
    this.ws = webSocket.createWebSocket()

    // 连接打开
    this.ws.on('open', () => {
      console.info('WebSocket 连接已建立')
    })

    // 接收消息
    this.ws.on('message', (error, data) => {
      if (!error) {
        this.messages.push(data as string)
      }
    })

    // 连接关闭
    this.ws.on('close', () => {
      console.info('WebSocket 连接已关闭')
    })

    // 连接错误
    this.ws.on('error', (error) => {
      console.error(`WebSocket 错误: ${error}`)
    })

    // 发起连接
    await this.ws.connect('wss://api.example.com/ws')
  }

  sendMessage(msg: string) {
    this.ws?.send(msg)
  }

  aboutToDisappear() {
    this.ws?.close()
  }

  build() {
    Column() {
      List() {
        ForEach(this.messages, (msg: string) => {
          ListItem() { Text(msg).fontSize(14) }
        })
      }

      Button('连接').onClick(() => this.connectWebSocket())
      Button('发送').onClick(() => this.sendMessage('你好'))
    }
  }
}

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式