HarmonyOS开发 - 电商App实例二( 网络请求http)

在HarmonyOS中进行网络请求开发时,可以使用"@ohos.net.http"库,该库支持常见的HTTP方法,能够满足大多数应用或元服务的需求。

接下来,我们将通过http库,对其进行二次封装,并向后台发送请求,完成banner数据的获取。

一、基本使用

1.1 导入模块

TypeScript 复制代码
import http from '@ohos.net.http'

1.2 http请求数据

首先,我们先看下@ohos.net.http的基本用法,使用http模块发送一个GET请求,处理响应。示例代码如下:

TypeScript 复制代码
import http from '@ohos.net.http';

// 创建 HTTP 请求对象
let httpRequest = http.createHttp();

// 发送 GET 请求
httpRequest.request(
    "https://api.example.com/data",
    {
        method: http.RequestMethod.GET,
        header: {
            'Content-Type': 'application/json'
        }
    },
    (err, data) => {
        if (err) {
            console.error('Error:', err);
        } else {
            console.log('Response Code:', data.responseCode);
            console.log('Response Data:', data.result);
        }
    }
);

1.3 HttpRequestOptions

参数如下表:

|----------------|----------------|---------------------------|
| 名称 | 类型 | 描述 |
| method | RequestMethod | 请求方式:GET、POST、PUT、DELETE等 |
| extraData | string|Object | 请求参数 |
| header | Object | 请求字段 |
| connectTimeout | number | 连接超时时间,单位毫秒,默认是60000ms |
| readTimeout | number | 读取超时时间,同上 |

1.4 HttpResponse

参数如下表:

|--------------|----------------|----------------|
| 名称 | 类型 | 描述 |
| responseCode | ResponseCode | 响应状态码 |
| header | Object | 响应头 |
| cookies | string | 响应返回的cookies |
| result | string|Object | 响应体,默认是JSON字符串 |
| resultType | HttpDataType | 返回值类型 |

二、Http库

官方提供的"@ohos.net.http库,支持常见的Http方法,如 get、post、options、head、put、delete、trace、connect等,为了简化网络请求的流程,更好地复用和管理代码,我们可以对@ohos.net.http进行封装,使其更易于使用。

在网络请求中,通常需要考虑以下几个方面:

  1. 请求方法:使用哪种Http方法(GET、POSt、PUT、DELETE)来发送请求。
  2. 请求头:设置必要的请求头,例如Content-Type、Authorization等。
  3. 请求体:对POST、PUT请求,可能需要发送请求体。请求体可以是Json数据、表单数据或文件等。
  4. 处理响应:处理网络请求过程中可能出现的错误,例如超时,网络不可用、服务器错误等。
  5. 异步处理:网络请求通常是异步的,需要使用回调、Promise、async/awai等机制来处理异步操作。
  6. 安全性:确保网络请求的安全性,例如使用HTTPS、验证证书、防止CSRF攻击等。

2.1 封装@ohos.net.http

为了简化代码并提高复用性,可以将@ohos.net.http封装成一个工具类。先在ets目录下创建utils目录,再创建httpUtil类(路径:ets/utils/httpUtil.ts)。代码如下:

TypeScript 复制代码
import http from '@ohos.net.http';

/**
 * http封装类
 */
export class HttpUtil {
  private base_url: string = '';  // 基础路径
  private headers: Record<string, string> | null = null; // header信息
  private httpRequest: http.HttpRequest; // request请求

  /**
   * 构造函数
   * @param url 基础路径
   * @param headers header信息
   */
  constructor(url?: string, headers?: Record<string, string>) {
    this.httpRequest = http.createHttp()
    if (url) this.base_url = url
    if (headers) this.headers = headers
  }

  /**
   * 设置基础路径
   * @param url
   */
  setBaseUrl(url: string) {
    this.base_url = url
  }

  /**
   * 设置header信息
   * @param headers
   */
  setHeaders(headers: Record<string, string>) {
    this.headers = headers
  }

  /**
   * 销毁 http 请求对象
   */
  public destroy(){
    this.httpRequest.destroy()
  }

  /**
   * 发送HTTP请求
   * @param url 请求地址
   * @param method  请求方法(如GET、POST、PUT、DELETE)
   * @param headers 请求头
   * @param data  请求体(仅用于 POST/PUT)
   * @returns 返回响应数据
   */
  public async request (
    url: string,
    method: http.RequestMethod = http.RequestMethod.GET,
    headers: Record<string, string> = {},
    data?: Record<string, any>
  ): Promise<any> {
    // 合并基础路径
    const _url = this.base_url ? this.base_url + url : url
    // 合并header信息
    const _headers = this.headers ? Object.assign({}, this.headers, headers) : !headers ? {} : headers
    return new Promise((resolve, reject) => {
      this.httpRequest.request(_url, {
        method: method,
        header: _headers,
        extraData: data
      }, (err, response) => {
        if (err) {
          reject(err)
        } else {
          // 如果请求成功,返回正确结果,否则返回错误信息
          if (response.responseCode == http.ResponseCode.OK) {
            resolve(response.result)
          } else {
            reject('HttP Error:' + response.responseCode)
          }
        }
      })
    })
  }

  /**
   * 发送 GET 请求
   * @param url 请求地址
   * @param headers 请求头
   * @returns 返回响应数据
   */
  public async get(url: string, headers?: Record<string, string>) : Promise<any> {
    return this.request(url, http.RequestMethod.GET, headers)
  }

  /**
   * 发送 POST请求
   * @param url 请求地址
   * @param data 请求体
   * @param headers 请求头
   * @returns 返回响应数据
   */
  public async post(url: string, data: Record<string, any>, headers?: Record<string, string>) : Promise<any> {
    return this.request(url, http.RequestMethod.POST, headers, data)
  }
}

2.2 实例httpUtil类

在utils目录中,再创建request请求文件(路径:ets/utils/request.ts),用于初始化http请求的基础路径和header请求类型信息,并且全局共享该实例对象。示例代码如下:

TypeScript 复制代码
import { HttpUtil } from './httpUtil'

/**
 * 初始化请求 实例类
 */
export const httpRequest = new HttpUtil('http://test.shop.com', {
  'Content-Type': 'application/json'
})

2.3 api请求

在api目录创建,创建index.ts文件,用于定义具体业务请求函数。这里向后台发送一个GET请求,用于获取banner信息。示例代码如下:

TypeScript 复制代码
import { httpRequest } from '../utils/request'

/**
 * 获取banner信息
 */
export const getBannerInfo = async () => {
  return await httpRequest.get('/banner.php')
}

2.4 获取banner信息

如下图,在页面中添加按钮,点击"获取banner信息",向后台发送GET请求,获取banner数据。

打开pages/index.ets 页面文件,添加http请求。代码如下:

TypeScript 复制代码
import { getBannerInfo } from '../api/index'

@Entry
@Component
struct Index {
  @State bannerMessage: string = '';

  build() {
    RelativeContainer() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }){
        Text(this.bannerMessage)

        Button('获取banner信息').onClick(async () => {
          console.log('tag')
          await getBannerInfo().then(res => {
            this.bannerMessage = JSON.stringify(res)
            console.log('tas success', res)
          }).catch(() => {
            console.error('Error')
          })
        })
      }.width('100%')
    }
    .height('100%')
    .width('100%')
  }
}

但是,大家会发现Promise回调结果 res变量下方出现了波浪线,并提示错误为:Use explicit types instead of "any", "unknown" (arkts-no-any-unknown) <ArkTSCheck>。这是因为在ArkTS中,使用any或unknow 类型会降低代码的类型的安全性,因此需要使用显式类来替代它们,确保类型安全。

2.5 定义接口

下面为请求和响应的数据类型定义明确的接口,并使用泛型来增强类型安全性。在types目录中创建http.d.ts文件,用于定义http的接口。代码如下:

TypeScript 复制代码
import http from '@ohos.net.http';

// 定义请求参数接口
interface RequestOptions {
  url: string;
  method?: http.RequestMethod,
  headers?: Record<string, string>;
  data?: Record<string, any>;
  timeout?: number
}

// 定义响应数据接口
interface HttpResponse<T> {
  responseCode: number;
  result: T;
}

2.6 httpUtil改造

将定义的接口数据引入到httpUtil.ts中,对request、get、post等方法,增加泛型,通过显示类类型定义,确保请求和响应的数据类型一致。改造后的httpUtils 代码如下:

TypeScript 复制代码
import http from '@ohos.net.http';
import { HttpResponse, RequestOptions } from '../types/http';

/**
 * http封装类
 */
export class HttpUtil {
  private base_url: string = '';  // 基础路径
  private headers: Record<string, string> | null = null; // header信息
  private httpRequest: http.HttpRequest; // request请求

  /**
   * 构造函数
   * @param url 基础路径
   * @param headers header信息
   */
  constructor(url?: string, headers?: Record<string, string>) {
    this.httpRequest = http.createHttp()
    if (url) this.base_url = url
    if (headers) this.headers = headers
  }

  /**
   * 设置基础路径
   * @param url
   */
  setBaseUrl(url: string) {
    this.base_url = url
  }

  /**
   * 设置header信息
   * @param headers
   */
  setHeaders(headers: Record<string, string>) {
    this.headers = headers
  }

  /**
   * 销毁 http 请求对象
   */
  public destroy(){
    this.httpRequest.destroy()
  }

  /**
   * 发送HTTP请求
   * @param options 请求参数
   * @returns 返回响应数据
   */
  public async request <T> (options : RequestOptions ): Promise<T> {
    // 合并基础路径
    const _url = this.base_url ? this.base_url + options.url : options.url
    // 合并header信息
    const _headers = this.headers ? Object.assign({}, this.headers, options.headers) :
                      !options.headers ? {} : options.headers
    return new Promise((resolve, reject) => {
      this.httpRequest.request(_url, {
        method: options.method || http.RequestMethod.GET,
        header: _headers,
        extraData: options.data || {},
        readTimeout: options.timeout || 5000,
        connectTimeout: options.timeout || 5000
      }, (err, response) => {
        if (err) {
          reject(err)
        } else {
          // 如果请求成功,返回正确结果,否则返回错误信息
          if (response.responseCode == http.ResponseCode.OK) {
            resolve(response.result as T)
          } else {
            reject('HttP Error:' + response.responseCode)
          }
        }
      })
    })
  }

  /**
   * 发送 GET 请求
   * @param url 请求地址
   * @param headers 请求头
   * @returns 返回响应数据
   */
  public async get <T> (url: string, headers?: Record<string, string>) : Promise<T> {
    return this.request <T> ({url, method: http.RequestMethod.GET, headers})
  }

  /**
   * 发送 POST请求
   * @param url 请求地址
   * @param data 请求体
   * @param headers 请求头
   * @returns 返回响应数据
   */
  public async post <T> (
    url: string, data: Record<string, any>, headers?: Record<string, string>
  ) : Promise<T> {
    return this.request({url, method: http.RequestMethod.POST, headers, data })
  }
}

2.7 api更改

定义banner信息数据类型,在发起get请求位置,将类型传入进去。代码如下:

TypeScript 复制代码
interface apiBanner {
  id: number;
  name: string;
  thumb: string;
  uid: number;
  createTime: Date;
  updateTime: Date;
}

/**
 * 获取banner信息
 */
export const getBannerInfo = async () => {
  return await httpRequest.get<apiBanner>('/banner.php')
}

当httpUtil类和api请求改造好后,在页面中点击按钮,获取banner信息。如下图:

点击按钮后,getBannerInfo接口向后台发送了一个请求,成功获取了接口响应的数据,并通过Text组件将数据显示在App界面中。

在项目开发中,Http请求扮演着至关重要的角色,http请求是App与服务器之间进行数据交互的主要方式。通过发送http请求,App可以从服务器获取数据,如用户信息,产品信息等,也可以向服务器提交数据,如表单数据,文件上传等。这种数据交互是App实现各种功能的基础。

如果你有更多问题,欢迎随时沟通交流!

相关推荐
Stupid4 分钟前
[学习笔记] Elpis-core 的学习过程理解笔记
前端
the_flash5 分钟前
手写VueUse的onClickOutside函数
前端
小鱼冻干6 分钟前
node.js 文件流-可读取流
前端·node.js
飘尘6 分钟前
面试官:如何实现大量任务执行的调度?
前端·javascript·面试
印第安老斑鸠啊8 分钟前
微前端框架MicroApp本地开发改造篇--vite适配
前端
全栈若城9 分钟前
30.Harmonyos Next仿uv-ui 组件NumberBox 步进器组件事件处理
harmonyos
osspeace9 分钟前
使用husky+commitizen+semantic-release实现项目的全自动版本管理和发布
前端·javascript
Epicurus11 分钟前
使用transform: translate时出现闪烁现象如何解决
前端·css
前端卧龙人12 分钟前
别再重复造轮子,VueUse让前端开发更简单、更高效
前端
前端卧龙人12 分钟前
前端埋点与监控的核心要点
前端