【鸿蒙HarmonyOS】网络请求http代码实现

在网络开发中,HTTP请求是必不可少的一部分。在鸿蒙(HarmonyOS)开发中,同样需要处理网络请求,无论是与后端服务器交互还是获取外部API的数据。下面是对鸿蒙开发中涉及到的HTTP模块——http模块,以及一个常用的第三方库——axios模块的总结。

HTTP协议概述

1. 基本概念
  • 请求(Request):客户端向服务器发送的消息。
  • 响应(Response):服务器接收到请求后返回给客户端的消息。
  • 消息格式:HTTP消息由报文头(Header)、状态行(Status Line)和可选的实体主体(Entity Body)组成。
2. 请求报文结构
  • 请求行:包含请求方法、请求URI和协议版本。
    GET /index.html HTTP/1.1
    
  • 请求头:包含客户端的信息,如Accept-Language、User-Agent等。
    Accept-Language: zh-CN,zh;q=0.9
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3
    
  • 实体主体:可选部分,包含请求的具体内容,如表单数据或文件上传。
    username=admin&password=123456
    
3. 响应报文结构
  • 状态行:包含HTTP版本、状态码及状态描述。
    HTTP/1.1 200 OK
    
  • 响应头:包含服务器的信息,如Content-Type、Date等。
    Content-Type: text/html; charset=UTF-8
    Date: Thu, 01 Jan 2023 12:00:00 GMT
    
  • 实体主体:可选部分,包含响应的具体内容,如HTML文档。
4. 请求方法
  • GET:请求指定的资源。
  • POST:向指定资源提交数据进行处理请求(例如提交表单或者注册用户)。
  • PUT:替换目标资源。
  • DELETE:删除指定资源。
  • HEAD:类似于GET请求,但只返回头部信息。
  • OPTIONS:查询目标资源的通信选项。
  • PATCH:对资源进行部分更新。
5. 状态码
  • 1xx(信息响应类):指示请求已被接受,需要进一步处理。
  • 2xx(成功响应类):请求已成功被服务器接收、理解,并接受。
    • 200 OK:成功。
    • 201 Created:创建成功。
  • 3xx(重定向类):需要客户端采取进一步的操作来完成请求。
    • 301 Moved Permanently:永久重定向。
    • 302 Found:临时重定向。
  • 4xx(客户端错误类):请求中有错误,或请求无法被服务器理解。
    • 400 Bad Request:请求无效。
    • 401 Unauthorized:未经授权。
    • 403 Forbidden:禁止访问。
    • 404 Not Found:找不到资源。
  • 5xx(服务器错误类):服务器在处理请求的过程中发生了错误。
    • 500 Internal Server Error:内部服务器错误。
    • 503 Service Unavailable:服务不可用。

HTTP的工作原理

  1. 建立连接:客户端与服务器之间建立TCP连接。
  2. 发送请求:客户端发送HTTP请求到服务器。
  3. 处理请求:服务器接收请求,处理请求内容。
  4. 发送响应:服务器根据处理结果构建响应,并发送给客户端。
  5. 关闭连接:完成响应后,默认情况下会关闭连接(HTTP/1.0),或者保持连接开放以供后续请求使用(HTTP/1.1及以上版本)。

HTTP与HTTPS的区别

  • 安全性:HTTPS是在HTTP的基础上加入了SSL/TLS协议,用于加密传输的数据,增强安全性。
  • 端口号:HTTP默认端口为80,HTTPS默认端口为443。
  • 证书:HTTPS需要服务器端有数字证书支持,确保数据的完整性和机密性。

通过以上概述,你应该对HTTP协议有了更深入的理解。在实际开发中,根据不同的场景选择合适的请求方法和状态码,对于构建健壮的网络应用程序至关重要。

HarmonyOS HTTP模块

官方文档传送门

1. 概述

HarmonyOS提供了内置的http模块来实现HTTP请求。此模块允许开发者以异步的方式发起HTTP请求,支持GET、POST等多种HTTP方法。

基本用法

1. 导入
import { http } from '@kit.NetworkKit'
2. 创建请求对象
const req = http.createHttp()
3. 发送请求并获取响应
req.request('请求地址url')
  .then((res: http.HttpResponse) => {
    AlertDialog.show({ message: JSON.stringify(res) })
  })
注意事项
  • 预览器:无需配置网络权限即可成功发送请求。

  • 模拟器:需要配置网络权限才能成功发送请求。

  • 真机:需要配置网络权限才能成功发送请求。

  • 在HarmonyOS中,你需要在module.json5文件中配置网络权限。以下是详细的配置示例:


{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet",
      "2in1"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      }
    ],
    "extensionAbilities": [
      {
        "name": "EntryBackupAbility",
        "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
        "type": "backup",
        "exported": false,
        "metadata": [
          {
            "name": "ohos.extension.backup",
            "resource": "$profile:backup_config"
          }
        ]
      }
    ]
  }
}
// 代码示例
import { http } from '@kit.NetworkKit'

const req = http.createHttp()
req.request('请求地址url')
  .then((res: http.HttpResponse) => {
    AlertDialog.show({ message: JSON.stringify(res) })
  })
2. 主要方法

通过一个图书管理案例来详细了解一下http请求数据的基本使用,因为需要用到接口,我使用的是黑马程序员提供的在线接口文档链接仅供学习

在这里插入图片描述

完成效果

在这里插入图片描述

3. 示例代码

export interface IBook{
  /**
   * 响应数组
   */
  data: iBook[];
  /**
   * 响应消息
   */
  message: string;

}

export interface IBookdetail{
  /**
   * 响应数组
   */
  data: iBook;
  /**
   * 响应消息
   */
  message: string;
}
export interface iBook {
  /**
   * 图书作者
   */
  author: string;
  /**
   * 图书名字
   */
  bookname: string;
  /**
   * 图书id
   */
  id: number;
  /**
   * 图书出版社
   */
  publisher: string;
}

export  const creator='艾宝宝'

获取-图书列表 GET &&删除-图书 DELETE

import { IBook, iBook } from './databook'
import { http } from '@kit.NetworkKit'
import router from '@ohos.router'
import { promptAction } from '@kit.ArkUI'

@Entry
@Component
struct MyBook {
  @State ISfree: boolean = false
  @State books: iBook[] = []
  /**
   * 页面显示时调用的方法
   * 该方法在页面被显示时触发,用于获取书籍信息
   */
  onPageShow(): void {
    // 调用getbook方法获取书籍信息
    this.getbook()
      // 将返回的结果解析为IBook对象
      .then(res => {
        let obj: IBook = JSON.parse(res.result.toString())
        // 将解析后的书籍数据赋值给books属性
        this.books = obj.data
      })
  }
  /**
   * 获取书籍信息的方法
   * 该方法用于发起网络请求,获取指定创建者的书籍信息
   * @returns 返回一个Promise对象, resolve时携带HTTP响应
   */
  getbook() {
    // 创建HTTP请求对象
    const req = http.createHttp()
    // 发起网络请求,获取书籍信息
    return req.request('https://hmajax.itheima.net/api/books?creator=' + encodeURIComponent('艾宝宝'))
  }
  
  
  //顶部
  @Builder
  top() {
    Row() {
      Image($r('app.media.ic_public_drawer_filled'))
        .width(30)
      //点击弹窗,点击确认全部删除
        .onClick(()=>{
           promptAction.showDialog({
               title: '提示',
               message: '确定全部删除吗?',
               buttons: [
                   { text: '取消', color: '#ff161616' },
                   { text: '确认', color: '#ff2156c1' }
               ]
           }).then(res=>{
             // 根据响应的索引执行不同的操作
             if (res.index == 1) {
               // 创建HTTP请求对象
               const req = http.createHttp()
               // 向指定URL发送DELETE请求以删除数据
               req.request('https://hmajax.itheima.net/api/books', {
                 method: http.RequestMethod.DELETE
               })
                 .then(res => {
                   // 解析响应结果,根据id数组中的每个id向服务器发送删除请求
                   this.books.map((item)=>{
                     return  req.request('https://hmajax.itheima.net/api/books/' + item.id, {
                         method: http.RequestMethod.DELETE
                       })
                       .then(res => {
                         // 解析响应结果,显示提示信息
                         let obj: IBook = JSON.parse(res.result.toString())
                         promptAction.showToast({
                           message: `${obj.message}`
                         })
                         // 重新获取数据
                         this.getbook()
                           .then(res => {
                             let obj: IBook = JSON.parse(res.result.toString())
                             // 更新本地数据
                             this.books = obj.data
                           })
                       })

                   })
                 })
             }
           })
        })
      Text(`我的书架`).fontSize(25)
        .fontWeight(FontWeight.Bold)
      Image($r('app.media.ic_public_add'))
        .width(30)
        .onClick(() => {
          router.pushUrl({
            url: '/pages/addbook'.slice(1)
          })
        })
    }.width('100%')
    .padding(10)
    .justifyContent(FlexAlign.SpaceBetween)
    .border({ width: { bottom: 1 }, color: '#80000000' })

  }
  //图书列表
  @Builder
  list() {
    List() {
      ForEach(this.books, (item: iBook, index: number) => {
        ListItem() {
          Row({ space: 10 }) {
            Image($r('app.media.ic_public_cover'))
              .height(100)
            Column({ space: 20 }) {
              Column({ space: 10 }) {
                Text(`书名:` + item.bookname).width('100%').fontWeight(FontWeight.Bold)
                  .fontSize(18)
                Text(`作者:` + item.author).width('100%')
                  .fontSize(14)
                  .fontColor('#666666')
              }

              Text(`出版社:` + item.publisher).width('100%')
                .fontSize(14)
                .fontColor('#666666')
            }
            .layoutWeight(1)
          }.width('100%').height(100)
        }.padding(10)
        .swipeAction({ end: this.dle(item.id), })
        .onClick(() => {
          router.pushUrl({
            url: '/pages/alterbook'.slice(1),
            params: {
              id: item.id
            }
          })
        })
      })
    }.layoutWeight(1).scrollBar(BarState.Off)

  }
  //删除图标
  @Builder
  dle(id: number) {
    Column() {
      Text(`删除`)
        .fontColor('#ffffff')
        .fontWeight(FontWeight.Bold)

    }.width(70)
    .height('100%')
    .backgroundColor('red')
    .justifyContent(FlexAlign.Center)
    .onClick(()=>{
     promptAction.showDialog({
    title: '提示',
    message: '确定删除吗?',
    buttons: [
        { text: '确定', color: '#ff164ae0' },
        { text: '取消', color: '#ff1c1919' }
    ]
})
        .then(res=>{
            //AlertDialog.show({message:JSON.stringify(res,null,2)})
          //点击确定删除 ---索引顺序从0开始 左边是0
          if (res.index == 0) {
            const req = http.createHttp()
            req.request('https://hmajax.itheima.net/api/books/' + id, {
              method: http.RequestMethod.DELETE
            })
              .then(res => {
                let obj: IBook = JSON.parse(res.result.toString())
                promptAction.showToast({
                  message: `${obj.message}`
                })
                this.getbook()
                  .then(res => {
                   let obj: IBook = JSON.parse(res.result.toString())
                    this.books = obj.data
                  })
              })
          }
        })
    })
  }
  build() {
      Column() {
        //
        this.top()
        //正在加载的动画
        if (this.books.length == 0) {
          this.loading()
        }
        //
        this.list()
      }
      .padding(10)
      .width('100%')
      .height('100%')
  }
  //加载中占位图
  @Builder
  loading() {
    Row() {
      LoadingProgress()
        .width(50)
      Text(`加载中...`)
    }
  }
}

新增-图书 POST


// 导入创建者
import { creator, IBook } from './databook'
import { promptAction, router } from '@kit.ArkUI'
import { http } from '@kit.NetworkKit'

/*
 * 步骤
 * 1. 非空验证 -> 轻提示用户
 * ✔️2. 获取表单的值 -> 已经使用了$$完成
 * 3. 发出POST请求将数据提交给服务器
 * 4. 返回图书列表页面
 *
 * */
@Entry
@Component
struct addPage {
  @State bookname: string = ''
  @State author: string = ''
  @State publisher: string = ''

  // 新增的
  addSubmit() {
    //  1. 非空验证 -> 轻提示用户
    if (this.bookname == '' || this.author == '' || this.publisher == '') {
      promptAction.showToast({ message: '图书名,作者,出版社均非空' })
      return //阻止下面代码继续执行
    }
    // 3. 发出POST请求将数据提交给服务器
    const req = http.createHttp()
    req.request('https://hmajax.itheima.net/api/books', {
      method: http.RequestMethod.POST,
      header: {
        'Content-Type': 'application/json'
      },
      extraData: {
        bookname: this.bookname,
        author: this.author,
        publisher: this.publisher,
        creator: creator
      }
    }).then(res => {
      let obj: IBook = JSON.parse(res.result.toString())
      // 提示用户新增的结果
      promptAction.showToast({ message: obj.message })
      // 4. 返回图书列表页面
      // ✨✨注意:通过router.back()返回的页面是不会触发aboutToAppear这个函数的
      // 需要将其改成 onPageShow ,所以我们需要改造 BookListPage.ets中的生命周期方法
      // pushUrl -> 页面栈中每次都新增一个页面,最多只能32个,所以这里使用back方法来节省页面栈
      router.back()
    })
  }
  build() {
    Navigation() {
      Column({ space: 10 }) {
        Row() {
          Text('图书名称:')
          TextInput({ placeholder: '请输入图书名字', text: $$this.bookname })
        }
        Row() {
          Text('图书作者:')
          TextInput({ placeholder: '请输入作者名字', text: $$this.author })
        }
        Row() {
          Text('图书出版社:')
          TextInput({ placeholder: '请输入出版社名字', text: $$this.publisher })
        }
        Button({ type: ButtonType.Normal }) {
          Text('保存')
            .fontColor(Color.White)
            .fontWeight(800)
        }
        .width('100%')
        .height(40)
        .borderRadius(8)
        .onClick(() => {
          // 调用新增逻辑方法
          this.addSubmit()
        })
      }
      .height('100%')
      .width('100%')
      .padding(10)
    }
    .title('新增图书')
    .titleMode(NavigationTitleMode.Mini)
  }
}

修改-图书 PUT

import router from '@ohos.router'
import { creator, IBook, IBookdetail } from './databook'
import { http } from '@kit.NetworkKit'
import { promptAction } from '@kit.ArkUI'

interface BookId {
  id: number
}

@Entry
@Component
struct Alterbook {
  req = http.createHttp()
  @State bookid: number = 0
  creator: string = creator
  @State bookname: string = ''
  @State author: string = ''
  @State publisher: string = ''

  // 页面加载时,获取图书id,通过id获取图书信息  id(路由传参)
  aboutToAppear(): void {
    let obj = router.getParams() as BookId
    this.bookid = obj.id
    this.req.request('https://hmajax.itheima.net/api/books/' + this.bookid, {})
      .then(res => {
        let book: IBookdetail = JSON.parse(res.result.toString())
        this.bookname = book.data.bookname
        this.author = book.data.author
        this.publisher = book.data.publisher
      })
  }

  // creator: string = creator

  build() {
    Navigation() {
      Column({ space: 10 }) {
        Row() {
          Text(`图书名称:`)
          TextInput({
            placeholder: '请输入图书名称', text: $$this.bookname,
          }).layoutWeight(1)
            .backgroundColor('#fff')
        }.border({ width: { bottom: 1 }, color: '#ccc' })

        Row() {
          Text(`图书作者:`)
          TextInput({
            placeholder: '请输入图书作者',
            text: $$this.author,
          }).layoutWeight(1).backgroundColor('#fff')
            .backgroundColor('#fff')
        }.border({ width: { bottom: 1 }, color: '#ccc' })

        Row() {
          Text(`图书出版社:`)
          TextInput({
            placeholder: '请输入出版社',
            text: $$this.publisher,
          }).layoutWeight(1).backgroundColor('#fff')

        }.border({ width: { bottom: 1 }, color: '#ccc' })

        Button({ type: ButtonType.Normal }) {
          Text(`保存`)
            .fontSize(18)
            .fontColor('#fff')
            .fontWeight(FontWeight.Bold)

        }.width('100%').borderRadius(10)
        //将页面数据重新发送请求到服务器,修改完毕
        .onClick(() => {
          if (this.bookname == '' || this.author == '' || this.publisher == '') {
            promptAction.showToast({
              message: `请输入完整信息`,
              bottom: 350
            })

          } else {
            // 创建一个HTTP请求对象
            const req = http.createHttp()
            // 发送PUT请求以更新书籍信息
            req.request('https://hmajax.itheima.net/api/books/' + this.bookid, {
              // 设置请求方法为PUT
              method: http.RequestMethod.PUT,
              // 设置请求头,指定内容类型为JSON
              header: {
                'content-type': 'application/json'
              },
              // 设置请求体,包含需要更新的书籍信息
              extraData: {
                bookname: this.bookname,
                author: this.author,
                publisher: this.publisher,
                creator: creator
              }
              // 请求发送完成后执行的回调函数
              // 这里可以处理响应数据或者处理错误
            }).then(res => {
              let obj: IBook = JSON.parse(res.result.toString())
              promptAction.showToast({
                message: `${obj.message}`,
                bottom: 350
              })
              router.back()
            })
          }
        })
        .height(38)
      }.padding(15)
    }
    .title('编辑图书')
    .titleMode(NavigationTitleMode.Mini)
  }
}

Axios模块

1. 概述

Axios 是一个基于Promise的HTTP客户端,可以在浏览器和Node.js中使用。虽然HarmonyOS不是直接支持Node.js环境,但是可以通过npm安装axios并在HarmonyOS的应用中使用。
参考链接

2. 优点
  • 基于Promise:可以使用async/await语法编写更简洁的异步代码。
  • 支持浏览器和Node.js:具有良好的跨平台能力。
  • 易于使用:API简单易懂,文档丰富。
3. 安装

在HarmonyOS应用开发环境中,可以使用npm来安装axios:

# 安装
ohpm i @ohos/axios

# 卸载
ohpm uninstall @ohos/axios

使用示例

使用前在demo中entry–>src–>main–>ets–>common–>Common.ets文件中改为正确的服务器地址,在entry–>src–>main–>resources–>rawfile目录下添加正确的证书,才可正常的使用demo。

发起一个 GET 请求

axios支持泛型参数,由于ArkTS不再支持any类型,需指定参数的具体类型。 如:axios.get<T = any, R = AxiosResponse, D = any>(url)

  • T: 是响应数据类型。当发送一个 POST 请求时,客户端可能会收到一个 JSON 对象。T 就是这个 JSON 对象的类型。默认情况下,T 是 any,这意味着可以接收任何类型的数据。
  • R: 是响应体的类型。当服务器返回一个响应时,响应体通常是一个 JSON 对象。R 就是这个 JSON 对象的类型。默认情况下,R 是 AxiosResponse,这意味着响应体是一个 AxiosResponse 对象,它的 data 属性是 T 类型的
  • D: 是请求参数的类型。当发送一个 GET 请求时,可能会在 URL 中添加一些查询参数。D 就是这些查询参数的类型。参数为空情况下,D 是 null类型。
import axios from '@ohos/axios'
interface userInfo{
  id: number
  name: string,
  phone: number
}

// 向给定ID的用户发起请求
axios.get<userInfo, AxiosResponse<userInfo>, null>('/user?ID=12345')
.then((response: AxiosResponse<userInfo>)=> {
  // 处理成功情况
  console.info("id" + response.data.id)
  console.info(JSON.stringify(response));
})
.catch((error: AxiosError)=> {
  // 处理错误情况
  console.info(JSON.stringify(error));
})
.then(()=> {
  // 总是会执行
});

// 上述请求也可以按以下方式完成(可选)
axios.get<userInfo, AxiosResponse<userInfo>, null>('/user', {
  params: {
    ID: 12345
  }
})
.then((response:AxiosResponse<userInfo>) => {
  console.info("id" + response.data.id)
  console.info(JSON.stringify(response));
})
.catch((error:AxiosError) => {
  console.info(JSON.stringify(error));
})
.then(() => {
  // 总是会执行
});

// 支持async/await用法
async function getUser() {
  try {
        const response:AxiosResponse = await axios.get<string, AxiosResponse<string>, null>(this.getUrl);
        console.log(JSON.stringify(response));
      } catch (error) {
    console.error(JSON.stringify(error));
  }
}

发送一个 POST 请求

interface user {
  firstName: string,
  lastName: string
}
   axios.post<string, AxiosResponse<string>, user>('/user', {
     firstName: 'Fred',
     lastName: 'Flintstone'
   })
   .then((response: AxiosResponse<string>) => {
     console.info(JSON.stringify(response));
   })
   .catch((error) => {
  console.info(JSON.stringify(error));
});

发起多个并发请求

 const getUserAccount = ():Promise<AxiosResponse> => {
      return axios.get<string, AxiosResponse<string>, null>('/user/12345');
    }

 const getUserPermissions = ():Promise<AxiosResponse> => {
      return axios.get<string, AxiosResponse<string>, null>('/user/12345/permissions');
    }

 Promise.all<AxiosResponse>([getUserAccount(), getUserPermissions()])
 .then((results:AxiosResponse[]) => {
        const acct = results[0].data as string;
        const perm = results[1].data as string;
      });

使用说明

axios API
通过向 axios 传递相关配置来创建请求
axios(config)
// 发送一个get请求
axios<string, AxiosResponse<string>, null>({
  method: "get",
  url: 'https://www.xxx.com/info'
}).then((res: AxiosResponse) => {
  console.info('result:' + JSON.stringify(res.data));
}).catch((error: AxiosError) => {
  console.error(error.message);
})
axios(url[, config])
// 发送一个get请求(默认请求方式)
axios.get<string, AxiosResponse<string>, null>('https://www.xxx.com/info', { params: { key: "value" } })
.then((response: AxiosResponse) => {
  console.info("result:" + JSON.stringify(response.data));
})
.catch((error: AxiosError) => {
  console.error("result:" + error.message);
});
请求方法的 别名方式 来创建请求

为方便起见,为所有支持的请求方法提供了别名。

  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])

注意: 在使用别名方法时, url、method、data 这些属性都不必在配置中指定。

// 发送get请求
axios.get<string, AxiosResponse<string>, null>('https://www.xxx.com/info', { params: { key: "value" } })
.then((response: AxiosResponse) => {
  console.info("result:" + JSON.stringify(response.data));
})
.catch((error: AxiosError) => {
  console.error("result:" + error.message);
});

axios 实例

创建一个实例

您可以使用自定义配置新建一个实例。
axios.create([config])

const instance = axios.create({
  baseURL: 'https://www.xxx.com/info',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});
实例方法
  • axios#request(config)
  • axios#get(url[, config])
  • axios#delete(url[, config])
  • axios#post(url[, data[, config]])
  • axios#put(url[, data[, config]])
4. 图书案例示例代码–Axios

export interface iBookResponse {
  /**
   * 响应数组
   */
  data: iBookInfo[];
  /**
   * 响应消息
   */
  message: string;
}
export const  creator: string = 'baba'

// 按需导出
export interface iBookInfo {
  /**
   * 图书作者
   */
  author: string;
  /**
   * 图书名字
   */
  bookname: string;
  /**
   * 图书id
   */
  id: number;
  /**
   * 图书出版社
   */
  publisher: string;
}

获取-图书列表 GET &&
删除-图书 DELETE


import axios, { AxiosResponse } from '@ohos/axios'
import { iBookResponse, iBookInfo, creator } from './models'
import router from '@ohos.router'
import { promptAction } from '@kit.ArkUI'


const req = axios.create()

@Entry
@Component
struct Index {
  @State bookList: iBookInfo[] = []
  creator: string = creator

  //-------------------------
  onPageShow(): void {
    this.getList()
  }

  //-----------------请求数据渲染到列表
  async getList() {
    // 发起GET请求以获取图书数据
    let res: AxiosResponse<iBookResponse> =
      await req.request({
        url: 'https://hmajax.itheima.net/api/books',
        method: 'get',
        params: {
          creator: creator
        }
      })
    // 将请求响应中的图书数据赋值给bookList属性
    this.bookList = res.data.data
    //AlertDialog.show({message:JSON.stringify(res.data)})
  }

  // 1. 我的书架
  @Builder
  MyBook() {
    Row() {
      Image($r('app.media.ic_public_drawer_filled'))
        .height(20)//---------------点击全部删除
        .onClick(async () => {
          promptAction.showDialog({
            title: '提示',
            message: '确定删除吗?',
            buttons: [
              { text: '确定', color: '#ff164ae0' },
              { text: '取消', color: '#ff1c1919' }
            ]
          }) //根据点击结果,执行不同的操作
          //循环数组,每次根据id删除
         if (res.index == 0) {
          for (let i = 0; i < this.bookList.length; i++) {
            let res: AxiosResponse<iBookResponse> =
              await req.request({
                url: 'https://hmajax.itheima.net/api/books/' + this.bookList[i].id,
                method: 'delete'
              })
          }
          }
          //刷新列表 提示
          AlertDialog.show({ message: '全部删除成功' })
          this.getList()

        })
      Text('我的书架')
        .fontSize(20)
        .fontWeight(800)
      Image($r('app.media.ic_public_add'))
        .height(20)
        .onClick(() => {
          router.pushUrl({
            url: '/pages/Mbook/addPage'.slice(1),
          })
        })
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceBetween)
    .padding(10)
    .border({ width: { bottom: 1 }, color: { bottom: 'rgba(0,0,0,0.2)' } })
  }
  // 2. 书籍列表
  @Builder
  BookList() {
    List() {
      ForEach(this.bookList, (item: iBookInfo, index: number) => {
        ListItem() {
          // 布局
          Row({ space: 10 }) {
            Image($r('app.media.ic_public_cover'))
              .width(100)
            Column({ space: 25 }) {
              Column() {
                Text('书名:' + item.bookname)
                  .width('100%')
                  .fontSize(20)
                  .fontWeight(800)
                Text('作者:' + item.author)
                  .width('100%')
                  .fontSize(14)
                  .fontWeight(600)
                  .fontColor('rgba(0,0,0,0.4)')
                  .padding({ top: 5 })
              }
              Text('出版社:' + item.publisher)
                .width('100%')
                .fontWeight(600)
                .fontColor('rgba(0,0,0,0.4)')
            }
            .layoutWeight(1)
          }
          .padding(10)
          //-----------点击跳转编辑
          .onClick(() => {
            router.pushUrl({
              url: 'pages/Mbook/BjPage',
              params: {
                bookid: item.id
              }
            })
          })
        }
        .swipeAction({
          end: this.delBuilder(item.id)
        })
      })
    }
  }

  // 3. 删除书籍的构建函数
  @Builder
  delBuilder(id: number) {
    Column() {
      Text('删除')
        .backgroundColor(Color.Red)
        .fontColor(Color.White)
        .height('100%')
        .width(60)
        .textAlign(TextAlign.Center)
    }
    .padding(10)
    //点击提示确认删除
    .onClick(() => {
      promptAction.showDialog({
        title: '提示',
        message: '确定删除吗?',
        buttons: [
          { text: '确定', color: '#ff164ae0' },
          { text: '取消', color: '#ff1c1919' }
        ]
      })//根据点击结果,执行不同的操作
        .then(async (res) => {
          if (res.index == 0) {
            //删除
            let res: AxiosResponse<iBookResponse> =
              await req.request({
                url: 'https://hmajax.itheima.net/api/books/' + id,
                method: 'delete'
              })
            //删除成功,提示,刷新列表
            promptAction.showToast({
              message: '删除成功'
            })
            this.getList()
          }
        })
    })
  }
  build() {
    Column() {
      // 1. 我的书架
      this.MyBook()
      // 2. 书籍列表
      this.BookList()
    }
    .height('100%')
    .width('100%')
  }
}

新增-图书 POST

// 导入创建者
import axios, { AxiosResponse } from '@ohos/axios'
import { creator, iBookInfo, iBookResponse } from './models'
import { promptAction, router } from '@kit.ArkUI';

// POST请求体数据类型
export interface iReqeustBody {
  /**
   * 新增图书作者
   */
  author: string;
  /**
   * 新增图书名字
   */
  bookname: string;
  /**
   * 新增图书创建者,自己的外号,和获取图书时的外号相同
   */
  creator: string;
  /**
   * 新增图书出版社
   */
  publisher: string;
}
@Entry
@Component
struct addPage {
  @State bookname: string = ''
  @State author: string = ''
  @State publisher: string = ''
  creator: string = creator
  build() {
    Navigation() {
      Column({ space: 10 }) {
        Row() {
          Text('图书名称:')
          TextInput({ placeholder: '请输入图书名字', text: $$this.bookname })
        }

        Row() {
          Text('图书作者:')
          TextInput({ placeholder: '请输入作者名字', text: $$this.author })
        }

        Row() {
          Text('图书出版社:')
          TextInput({ placeholder: '请输入出版社名字', text: $$this.publisher })
        }

        Button({ type: ButtonType.Normal }) {
          Text('保存')
            .fontColor(Color.White)
            .fontWeight(800)
        }
        .width('100%')
        .height(40)
        .borderRadius(8)
        //保存更新图书
        .onClick(async () => {
          // 调用接口保存图书
          // 1. 创建一个请求对象
          let req = axios.create()
          // 2. 发送请求
          if (this.bookname == '' || this.author == '' || this.publisher == '') {
            promptAction.showToast({
              message: `请输入完整信息`,
              bottom: 350
            })
          } else {
            let res: AxiosResponse<iBookResponse> =
              await req.request({
                url: 'https://hmajax.itheima.net/api/books',
                method: 'post',
                data: {
                  bookname: this.bookname,
                  author: this.author,
                  publisher: this.publisher,
                  creator: creator
                } as iReqeustBody
              })
            // 提示  然后返回
            promptAction.showToast({
              message: `${res.data.message}`,
              bottom: 350
            })
            router.back()
          }
        })
      }
      .height('100%')
      .width('100%')
      .padding(10)
    }
    .title('新增图书')
    .titleMode(NavigationTitleMode.Mini)
  }
}

修改-图书 PUT

// 导入创建者
import { creator, iBookInfo, iBookResponse, } from './models'
import { router } from '@kit.ArkUI'
import axios, { AxiosResponse } from '@ohos/axios'

interface iRouterParams {
  bookid: number
}
interface iBookInfo1 {
  /**
   * 图书作者
   */
  author: string;
  /**
   * 图书名字
   */
  bookname: string;
  /**
   * 图书创建者,写上自己名字-管理自己的数据
   */
  creator: string;
  /**
   * 图书出版社
   */
  publisher: string;
}
export interface Putbook{
data:iBookInfo1
}

const req = axios.create()

@Entry
@Component
struct addPage {
  @State bookname: string = ''
  @State author: string = ''
  @State publisher: string = ''
  bookid: number = 0

  aboutToAppear(): void {
    //得到传过来的id
    let routerObj = router.getParams() as iRouterParams
    this.bookid = routerObj.bookid

    this.loadBook()
  }

  // 1. 回显图书数据
  async loadBook() {
    try {
      // 此处编写代码
      let res: AxiosResponse<Putbook> = await req.request({
        url: 'https://hmajax.itheima.net/api/books/' + this.bookid,
        method: 'get',

      })
      //AlertDialog.show({message:'获取图书数据成功'})
      this.bookname = res.data.data.bookname
      this.author = res.data.data.author
      this.publisher = res.data.data.publisher
    } catch (err) {
      console.error('err--->', JSON.stringify(err).slice(0,800))
    }
  }

  build() {
    Navigation() {
      Column({ space: 10 }) {
        Row() {
          Text('图书名称:')
          TextInput({ placeholder: this.bookname, text: $$this.bookname })
        }
        Row() {
          Text('图书作者:')
          TextInput({ placeholder: this.author, text: $$this.author })
        }
        Row() {
          Text('图书出版社:')
          TextInput({ placeholder: this.publisher, text: $$this.publisher })
        }
        Button({ type: ButtonType.Normal }) {
          Text('保存')
            .fontColor(Color.White)
            .fontWeight(800)
        }
        .width('100%')
        .height(40)
        .borderRadius(8)
//---------------点击修改并保存数据
        .onClick(async () => {
          let res: AxiosResponse<iBookResponse> =
            await req.request({
            url: 'https://hmajax.itheima.net/api/books/' + this.bookid,
            method: 'put',
            data: {
              bookname: this.bookname,
              author: this.author,
              publisher: this.publisher,
              creator: creator
            } as iBookInfo1
          })
          AlertDialog.show({message:'修改图书数据成功'})
          router.back()
        })
      }
      .height('100%')
      .width('100%')
      .padding(10)
    }
    .title('编辑  图书')
    .titleMode(NavigationTitleMode.Mini)
  }
}
5. 配置和拦截器
loding···
【http封装】 - 封装request泛型方法

我们发现网络请求的代码很多,且有些相似之处,我们把GET,POST进行封装之后请求就变得非常简单了,我把封装的类放下面:
新建一个.ets文件
loading·····(更新中···)

import axios, { AxiosResponse, AxiosError, AxiosRequestConfig } from '@ohos/axios'
import { iLoginUserModel, iResponseModel } from '../models/datamodel'
import { promptAction, router } from '@kit.ArkUI'

// 1. 准备一个axios的对象实例,同时设置好baseUrl
const req = axios.create({
baseURL: 'https://api-harmony-teach.itheima.net/'
})

export class HdHttp {
// 这个方法给外面专门做get请求调用的
static async Get<T>(url: string, paramsOrData?: object) {
  return await HdHttp.request<T>('GET', url, paramsOrData)
}

// 这个方法给外面专门做post请求调用的
static async Post<T>(url: string, paramsOrData?: object) {
  return await HdHttp.request<T>('POST', url, paramsOrData)
}

/*
method:表示服务器的请求方法,Get,POST,PUT,Delete
 url:代表的是服务器的url路径(不包含基本域名地址) ,例如:hm/studyInfo
 * paramsOrData:请求传参,可选
 *
 * T:代表的是服务器响应数据中的 data这个属性的类型
 * */
private static async request<T>(method: string, url: string, paramsOrData?: object) {
  try {
    //   1. 使用req来发送请求
    let reqConfig: AxiosRequestConfig = {
      method: method,
      url: url, //是请求接口的url路径部分,并且不带有/
    }
    // 2. 分请求类型来决定传参参数是parmas还是data
    if (method == 'GET') {
      reqConfig.params = paramsOrData
    } else {
      reqConfig.data = paramsOrData
    }

    // 3. 在请求前在header中携带token
    // 获取token
    let user = AppStorage.get<iLoginUserModel>('user')
    if (user && user.token) {
      reqConfig.headers = {
        'Authorization': `Bearer ${user.token}`
      }
    }

    let res: AxiosResponse<iResponseModel<T>> = await req.request(reqConfig)

    // 4. 处理服务器响应体中的code值为非10000的情况
    if (res.data.code != 10000) {
      //  将服务器的逻辑问题信息提示给用户
      promptAction.showToast({ message: res.data.message })
      return Promise.reject(res.data.message) //传递给外部调用者的 catch()中的信息
    }
    //   3. 返回结果(返回的是服务器的响应报文体的数据)
    return res.data

  } catch (err) {
    //  当服务器的http状态码为非200,就会执行catch
    let errObj: AxiosError = err
    // 判断服务器的响应状态码如果是401,表示token失效,此时应该提示用户和跳转到登录页面
    if (errObj.response?.status == 401) {
      promptAction.showToast({ message: '登录已失效,请重新登录' })
      router.replaceUrl({ url: 'pages/LoginPage' })
    } else {
      //  提示用户是什么错误即可
      promptAction.showToast({ message: '网络异常:' + errObj.message })
    }
    // AlertDialog.show({ message: 'err:' + JSON.stringify(errObj.response?.status, null, 2) })
    return Promise.reject(errObj.message) //传递给外部调用者的 catch()中的信息 外面使用者使用try{}catch(err){}
  }
}
}

调用封装好的类进行代码实现

loading·····

总结

  • HarmonyOS内置的HTTP模块:提供了基本的HTTP请求功能,适合简单的网络通信需求。
  • Axios:提供了更丰富的功能和更好的用户体验,尤其是对于需要更复杂请求处理的应用来说,是一个不错的选择。

选择哪个模块取决于你的具体需求和偏好。如果你的应用需要与Web服务紧密集成并且需要更多的功能,那么axios可能是更好的选择;而对于简单的HTTP请求,HarmonyOS自带的HTTP模块就足够了。

  • 39
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值