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

打印 上一主题 下一主题

主题 1935|帖子 1935|积分 5805

        在HarmonyOS中进行网络请求开发时,可以利用"@ohos.net.http"库,该库支持常见的HTTP方法,可以或许满意大多数应用或元服务的需求。
        接下来,我们将通过http库,对其进行二次封装,并向后台发送请求,完成banner数据的获取。

一、根本利用

1.1 导入模块

  1. import http from '@ohos.net.http'
复制代码
1.2 http请求数据

        首先,我们先看下@ohos.net.http的根本用法,利用http模块发送一个GET请求,处理相应。示例代码如下:
  1. import http from '@ohos.net.http';
  2. // 创建 HTTP 请求对象
  3. let httpRequest = http.createHttp();
  4. // 发送 GET 请求
  5. httpRequest.request(
  6.     "https://api.example.com/data",
  7.     {
  8.         method: http.RequestMethod.GET,
  9.         header: {
  10.             'Content-Type': 'application/json'
  11.         }
  12.     },
  13.     (err, data) => {
  14.         if (err) {
  15.             console.error('Error:', err);
  16.         } else {
  17.             console.log('Response Code:', data.responseCode);
  18.             console.log('Response Data:', data.result);
  19.         }
  20.     }
  21. );
复制代码

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进行封装,使其更易于利用。
        在网络请求中,通常需要考虑以下几个方面:

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

2.1 封装@ohos.net.http

        为了简化代码并提高复用性,可以将@ohos.net.http封装成一个工具类。先在ets目次下创建utils目次,再创建httpUtil类(路径:ets/utils/httpUtil.ts)。代码如下:
  1. import http from '@ohos.net.http';
  2. /**
  3. * http封装类
  4. */
  5. export class HttpUtil {
  6.   private base_url: string = '';  // 基础路径
  7.   private headers: Record<string, string> | null = null; // header信息
  8.   private httpRequest: http.HttpRequest; // request请求
  9.   /**
  10.    * 构造函数
  11.    * @param url 基础路径
  12.    * @param headers header信息
  13.    */
  14.   constructor(url?: string, headers?: Record<string, string>) {
  15.     this.httpRequest = http.createHttp()
  16.     if (url) this.base_url = url
  17.     if (headers) this.headers = headers
  18.   }
  19.   /**
  20.    * 设置基础路径
  21.    * @param url
  22.    */
  23.   setBaseUrl(url: string) {
  24.     this.base_url = url
  25.   }
  26.   /**
  27.    * 设置header信息
  28.    * @param headers
  29.    */
  30.   setHeaders(headers: Record<string, string>) {
  31.     this.headers = headers
  32.   }
  33.   /**
  34.    * 销毁 http 请求对象
  35.    */
  36.   public destroy(){
  37.     this.httpRequest.destroy()
  38.   }
  39.   /**
  40.    * 发送HTTP请求
  41.    * @param url 请求地址
  42.    * @param method  请求方法(如GET、POST、PUT、DELETE)
  43.    * @param headers 请求头
  44.    * @param data  请求体(仅用于 POST/PUT)
  45.    * @returns 返回响应数据
  46.    */
  47.   public async request (
  48.     url: string,
  49.     method: http.RequestMethod = http.RequestMethod.GET,
  50.     headers: Record<string, string> = {},
  51.     data?: Record<string, any>
  52.   ): Promise<any> {
  53.     // 合并基础路径
  54.     const _url = this.base_url ? this.base_url + url : url
  55.     // 合并header信息
  56.     const _headers = this.headers ? Object.assign({}, this.headers, headers) : !headers ? {} : headers
  57.     return new Promise((resolve, reject) => {
  58.       this.httpRequest.request(_url, {
  59.         method: method,
  60.         header: _headers,
  61.         extraData: data
  62.       }, (err, response) => {
  63.         if (err) {
  64.           reject(err)
  65.         } else {
  66.           // 如果请求成功,返回正确结果,否则返回错误信息
  67.           if (response.responseCode == http.ResponseCode.OK) {
  68.             resolve(response.result)
  69.           } else {
  70.             reject('HttP Error:' + response.responseCode)
  71.           }
  72.         }
  73.       })
  74.     })
  75.   }
  76.   /**
  77.    * 发送 GET 请求
  78.    * @param url 请求地址
  79.    * @param headers 请求头
  80.    * @returns 返回响应数据
  81.    */
  82.   public async get(url: string, headers?: Record<string, string>) : Promise<any> {
  83.     return this.request(url, http.RequestMethod.GET, headers)
  84.   }
  85.   /**
  86.    * 发送 POST请求
  87.    * @param url 请求地址
  88.    * @param data 请求体
  89.    * @param headers 请求头
  90.    * @returns 返回响应数据
  91.    */
  92.   public async post(url: string, data: Record<string, any>, headers?: Record<string, string>) : Promise<any> {
  93.     return this.request(url, http.RequestMethod.POST, headers, data)
  94.   }
  95. }
复制代码

2.2 实例httpUtil类

        在utils目次中,再创建request请求文件(路径:ets/utils/request.ts),用于初始化http请求的底子路径和header请求类型信息,而且全局共享该实例对象。示例代码如下:
  1. import { HttpUtil } from './httpUtil'
  2. /**
  3. * 初始化请求 实例类
  4. */
  5. export const httpRequest = new HttpUtil('http://test.shop.com', {
  6.   'Content-Type': 'application/json'
  7. })
复制代码

2.3 api请求

        在api目次创建,创建index.ts文件,用于定义具体业务请求函数。这里向后台发送一个GET请求,用于获取banner信息。示例代码如下:
  1. import { httpRequest } from '../utils/request'
  2. /**
  3. * 获取banner信息
  4. */
  5. export const getBannerInfo = async () => {
  6.   return await httpRequest.get('/banner.php')
  7. }
复制代码

2.4 获取banner信息

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

        打开pages/index.ets 页面文件,添加http请求。代码如下:
  1. import { getBannerInfo } from '../api/index'
  2. @Entry
  3. @Component
  4. struct Index {
  5.   @State bannerMessage: string = '';
  6.   build() {
  7.     RelativeContainer() {
  8.       Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }){
  9.         Text(this.bannerMessage)
  10.         Button('获取banner信息').onClick(async () => {
  11.           console.log('tag')
  12.           await getBannerInfo().then(res => {
  13.             this.bannerMessage = JSON.stringify(res)
  14.             console.log('tas success', res)
  15.           }).catch(() => {
  16.             console.error('Error')
  17.           })
  18.         })
  19.       }.width('100%')
  20.     }
  21.     .height('100%')
  22.     .width('100%')
  23.   }
  24. }
复制代码
        但是,各人会发现Promise回调结果 res变量下方出现了波浪线,并提示错误为:Use explicit types instead of "any", "unknown" (arkts-no-any-unknown) <ArkTSCheck>。这是因为在ArkTS中,利用any或unknow 类型会降低代码的类型的安全性,因此需要利用显式类来替换它们,确保类型安全。


2.5 定义接口

        下面为请求和相应的数据类型定义明白的接口,并利用泛型来加强类型安全性。在types目次中创建http.d.ts文件,用于定义http的接口。代码如下:
  1. import http from '@ohos.net.http';
  2. // 定义请求参数接口
  3. interface RequestOptions {
  4.   url: string;
  5.   method?: http.RequestMethod,
  6.   headers?: Record<string, string>;
  7.   data?: Record<string, any>;
  8.   timeout?: number
  9. }
  10. // 定义响应数据接口
  11. interface HttpResponse<T> {
  12.   responseCode: number;
  13.   result: T;
  14. }
复制代码

2.6 httpUtil改造

       将定义的接口数据引入到httpUtil.ts中,对request、get、post等方法,增加泛型,通过表现类类型定义,确保请求和相应的数据类型一致。改造后的httpUtils 代码如下:
  1. import http from '@ohos.net.http';
  2. import { HttpResponse, RequestOptions } from '../types/http';
  3. /**
  4. * http封装类
  5. */
  6. export class HttpUtil {
  7.   private base_url: string = '';  // 基础路径
  8.   private headers: Record<string, string> | null = null; // header信息
  9.   private httpRequest: http.HttpRequest; // request请求
  10.   /**
  11.    * 构造函数
  12.    * @param url 基础路径
  13.    * @param headers header信息
  14.    */
  15.   constructor(url?: string, headers?: Record<string, string>) {
  16.     this.httpRequest = http.createHttp()
  17.     if (url) this.base_url = url
  18.     if (headers) this.headers = headers
  19.   }
  20.   /**
  21.    * 设置基础路径
  22.    * @param url
  23.    */
  24.   setBaseUrl(url: string) {
  25.     this.base_url = url
  26.   }
  27.   /**
  28.    * 设置header信息
  29.    * @param headers
  30.    */
  31.   setHeaders(headers: Record<string, string>) {
  32.     this.headers = headers
  33.   }
  34.   /**
  35.    * 销毁 http 请求对象
  36.    */
  37.   public destroy(){
  38.     this.httpRequest.destroy()
  39.   }
  40.   /**
  41.    * 发送HTTP请求
  42.    * @param options 请求参数
  43.    * @returns 返回响应数据
  44.    */
  45.   public async request <T> (options : RequestOptions ): Promise<T> {
  46.     // 合并基础路径
  47.     const _url = this.base_url ? this.base_url + options.url : options.url
  48.     // 合并header信息
  49.     const _headers = this.headers ? Object.assign({}, this.headers, options.headers) :
  50.                       !options.headers ? {} : options.headers
  51.     return new Promise((resolve, reject) => {
  52.       this.httpRequest.request(_url, {
  53.         method: options.method || http.RequestMethod.GET,
  54.         header: _headers,
  55.         extraData: options.data || {},
  56.         readTimeout: options.timeout || 5000,
  57.         connectTimeout: options.timeout || 5000
  58.       }, (err, response) => {
  59.         if (err) {
  60.           reject(err)
  61.         } else {
  62.           // 如果请求成功,返回正确结果,否则返回错误信息
  63.           if (response.responseCode == http.ResponseCode.OK) {
  64.             resolve(response.result as T)
  65.           } else {
  66.             reject('HttP Error:' + response.responseCode)
  67.           }
  68.         }
  69.       })
  70.     })
  71.   }
  72.   /**
  73.    * 发送 GET 请求
  74.    * @param url 请求地址
  75.    * @param headers 请求头
  76.    * @returns 返回响应数据
  77.    */
  78.   public async get <T> (url: string, headers?: Record<string, string>) : Promise<T> {
  79.     return this.request <T> ({url, method: http.RequestMethod.GET, headers})
  80.   }
  81.   /**
  82.    * 发送 POST请求
  83.    * @param url 请求地址
  84.    * @param data 请求体
  85.    * @param headers 请求头
  86.    * @returns 返回响应数据
  87.    */
  88.   public async post <T> (
  89.     url: string, data: Record<string, any>, headers?: Record<string, string>
  90.   ) : Promise<T> {
  91.     return this.request({url, method: http.RequestMethod.POST, headers, data })
  92.   }
  93. }
复制代码

2.7 api更改

        定义banner信息数据类型,在发起get请求位置,将类型传入进去。代码如下:
  1. interface apiBanner {
  2.   id: number;
  3.   name: string;
  4.   thumb: string;
  5.   uid: number;
  6.   createTime: Date;
  7.   updateTime: Date;
  8. }
  9. /**
  10. * 获取banner信息
  11. */
  12. export const getBannerInfo = async () => {
  13.   return await httpRequest.get<apiBanner>('/banner.php')
  14. }
复制代码
        当httpUtil类和api请求改造好后,在页面中点击按钮,获取banner信息。如下图:

        点击按钮后,getBannerInfo接口向后台发送了一个请求,成功获取了接口相应的数据,并通过Text组件将数据表现在App界面中。
        在项目开发中,Http请求扮演着至关重要的角色,http请求是App与服务器之间进行数据交互的主要方式。通过发送http请求,App可以从服务器获取数据,如用户信息,产物信息等,也可以向服务器提交数据,如表单数据,文件上传等。这种数据交互是App实现各种功能的底子。
        假如你有更多题目,接待随时沟通交换!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表