鸿蒙中网络请求如何实现

452 阅读6分钟

1 HTTP 请求

1.1 HTTP数据请求

什么是HTTP数据请求 ?

(鸿蒙)应用软件可以通过(鸿蒙)系统内置的 http 模块,通过 HTTP 协议服务器进行通讯

核心概念:

  1. 什么是服务器

服务器是一种用于处理网络请求和提供服务的计算机系统或设备。它通常运行特定的软件程序,能够响应客户端的请求并返回相应的数据或服务。

在鸿蒙(HarmonyOS)开发中,服务器域名是指用于标识服务器的域名。配置服务器域名是为了确保元服务在上架前通过域名访问进行安全可靠的网络环境配置。

  1. 什么是HTTP模块

HTTP模块提供了HTTP数据请求的能力。开发者可以通过HTTP模块发起各种常见的HTTP请求,如GET、POST、PUT、DELETE等方法。

  1. 什么是HTTP协议

规定了客户端和服务端返回内容的格式

在通讯的时候必须按照格式发送内容才可以进行通信

1.2 http模块基本用法

ohos.net.http (数据请求)

基本用法

// 1. 导入http模块
import http from '@ohos.net.http'
//import { http } from '@kit.NetworkKit'

// 2. 创建请求对象
const req = http.createHttp()
// 3. 根据提供好的 地址发送请求,并在 then 中获取服务器响应的内容
req.request('请求地址url')
  .then((res: http.HttpResponse) => {
    AlertDialog.show({ message: JSON.stringify(res) })
  })

注意事项

1.预览器,模拟器,真机都可以发送http请求

预览器无需配置网络权限即可发送

模拟器和真机需要配置网络权限

2.配置网络权限-->需要在项目的src/main/module.json5(模块配置)

    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ],

1.3 认识URL

URL 代表着是统一资源定位符(Uniform Resource Locator)。URL 无非就是一个给定的独特资源在 网络上的地址。

理论上说,每个有效的 URL 都指向一个唯一的资源。这个资源可以是一个HTML网页,一个 CSS 文档,一张图片,一个视频,一个音频,甚至是一组数据等等

image.png

2 JSON

JSON 是一种按照 JavaScript 对象语法的数据格式,虽然它是基于 JavaScript 语法,但它独立于 JavaScript,许多【程序环境】能够读取(解读)和生成 JSON。

语法规则

  1. 是一个字符串(配置文件中两边可以不写引号)
  2. 属性名用双引号包裹,
  3. 属性值如果是字符串也必须用双引号包裹
  4. 对象 {} ,数组 []

3 HTTP协议

HTTP协议规定了浏览器发送及服务器返回内容的格式

image.png

3.1 请求报文

请求报文的组成部分:

  1. 请求行:请求方法,URL,协议(第一行)
  2. 请求头:以键值对的格式携带的附加信息,比如:Content-Type(第二行开始到空行)
  3. 空行:分隔请求头,空行之后的是发送给服务器的资源(空行)
  4. 请求体:发送的资源(空行之后)

3.2 响应报文

响应报文组成:

  1. 响应行(状态行) :协议、HTTP响应状态码、状态信息(第一行)
  2. 响应头:以键值对的格式携带的附加信息,比如:Content-Type(第一行到空行)
  3. 空行:分隔响应头,空行之后的是服务器返回的资源(空行)
  4. 响应体:返回的资源(空行之后)

4 请求库-axios

4.1 基本用法

4.1.1 下载AXIOS

# 安装
ohpm i @ohos/axios

# 卸载
ohpm uninstall @ohos/axios

image.png

4.1.2 POST请求

axios.post<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类型。
// 1. 导包
import axios, { AxiosResponse } from '@ohos/axios';

export interface iRequestData {
  password?: string;
  username?: string;
}

export interface iResponseData {
  code: number;
  message: string;
}

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button('axios post')
        .onClick(async () => {
          // 2. 创建axios实例
          const req = axios.create()
          // 3. 发送请求
          try {
            /*
             * 三个泛型参数
             * 第一个 表示响应类型
             * 第二个 表示响应体类型  AxiosResponse<写接口返回的数据interface>
             * 第三个 表示请求体类型
             */
            let res: AxiosResponse<iResponseData> =
              await req.request<null, AxiosResponse<iResponseData>, iRequestData>({
                url: 'https://hmajax.itheima.net/api/login',
                method: 'post',
                data: {
                  username: 'jack123456',
                  password: '12345678'
                }
              })
            AlertDialog.show({ message: JSON.stringify(res.data.message) })
          } catch (err) {
            AlertDialog.show({
              message: err
            })
          }
        })
    }
    .width('100%')
    .height('100%')
  }
}

4.1.3 GET请求

// 导入
import axios, { AxiosResponse } from '@ohos/axios'
interface JokeResponse {
  msg: string
  code: number
  data: string[]
}
@Entry
@Component
struct notebook_page {
  build() {
    Column({ space: 20 }) {

      Button('get 无参数')
        .onClick(async () => {
          const req = axios.create()
          try {
            let res: AxiosResponse<string> = await req.request({
              url: 'https://api-vue-base.itheima.net/api/joke',
              method: 'get',
            })
            AlertDialog.show({
              message: res.data
            })
          } catch (err) {
            AlertDialog.show({
              message: err
            })
          }
        })
      Button('get 有参数')
        .onClick(async () => {
          const req = axios.create()
          try {
            let res: AxiosResponse<JokeResponse> = await req.request({
              url: 'https://api-vue-base.itheima.net/api/joke/list',
              method: 'get',
              params: {
                num: '2'
              }
            })
            AlertDialog.show({
              message: JSON.stringify(res.data.data)
            })
            console.log(``, JSON.stringify(res.data.data))
          } catch (err) {
            AlertDialog.show({
              message: err
            })
          }
        })
    }
    .width('100%')
    .height('100%')
    .padding(15)
  }
}

4.2 基地址配置

// 导入
import axios, { AxiosResponse } from '@ohos/axios'

// 基地址
const req = axios.create({
  baseURL: 'https://api-vue-base.itheima.net'
})

Button('get 无参数')
  .onClick(async () => {
    try {
      let res: AxiosResponse<string> = await req.request({
        url: '/api/joke',
        method: 'get',
      })
      AlertDialog.show({
        message: res.data
      })
    } catch (err) {
      AlertDialog.show({
        message: err
      })
    }

  })
Button('get 有参数')
  .onClick(async () => {
    try {
      let res: AxiosResponse<JokeResponse> = await req.request({
        url: '/api/joke/list',
        method: 'get',
        params: {
          num: '2'
        }
      })
      AlertDialog.show({
        message: JSON.stringify(res.data.data)
      })
      console.log(``, JSON.stringify(res.data.data))
    } catch (err) {
      AlertDialog.show({
        message: err
      })
    }
  })

5 综合案例-我的书架-axios

5.1 get请求

http

req.request('https://hmajax.itheima.net/api/books?creator=r')
  .then(res => {
    let obj: IBookResult = JSON.parse(res.result.toString())
    this.bookList = obj.data
  })

axios

async getBookList() {
  try {
    let res: AxiosResponse<IBookResult> = await req.request({
      url: '/api/books',
      method: 'get',
      params: {
        creator: 'xxx'
      }
    })
    this.bookList = res.data.data
  } catch (err) {
    console.log(`rhj`, JSON.stringify(err.message))
  }
}

5.2 post请求

http

req.request(`https://hmajax.itheima.net/api/books`, {
  method: http.RequestMethod.POST,
  header: { contentType: 'application/json' },
  extraData: {
    bookname: this.bookname,
    author: this.author,
    publisher: this.publisher,
    creator: 'ivan'
  }
})
  .then(res => {
    let obj: IBookResult = JSON.parse(res.result.toString())
    promptAction.showToast({
      message: obj.message
    })
    router.back()
  })

axios

try {
  let res: AxiosResponse<IBookRes> = await req.request<null, AxiosResponse<IBookRes>, IBookInfo>({
    url: '/api/books',
    method: 'post',
    data: {
      bookname: this.bookname,
      author: this.author,
      publisher: this.publisher,
      creator: 'xxx',
      id: Date.now()

    }
  })
  promptAction.showToast({
    message: res.data.message
  })
  router.back()
} catch (err) {
  console.log(`rhj`, JSON.stringify(err))
}

5.3 put请求

http

req.request(`https://hmajax.itheima.net/api/books/${this.bookid}`, {
  method: http.RequestMethod.PUT,
  header: { contentType: 'application/json' },
  extraData: {
    bookname: this.bookname,
    author: this.author,
    publisher: this.publisher,
    creator: 'ivan'
  }
})
  .then(res => {
    let obj: IBookRes = JSON.parse(res.result.toString())
    promptAction.showToast({
      message: obj.message
    })
    router.back()
  })

axios

try {
  let res: AxiosResponse<IBookRes> = await req.request<null, AxiosResponse<IBookRes>, IBookInfo>({
    url: `api/books/${this.bookid}`,
    method: 'put',
    data: {
      id: this.bookid,
      bookname: this.bookname,
      author: this.author,
      publisher: this.publisher,
      creator: 'xxx'
    }
  })
  promptAction.showToast({
    message: res.data.message
  })
  router.back()

} catch (err) {
console.log(``, JSON.stringify(err))

}

5.4 delete请求

http

req.request(`https://hmajax.itheima.net/api/books/${item.id}`, {
  method: http.RequestMethod.DELETE
})
  .then(res => {
    let obj: IBookResult = JSON.parse(res.result.toString())
    promptAction.showToast({
      message: obj.message
    })
    this.getBookList()
  })

axios

try {
  let res: AxiosResponse<IBookRes> = await req.request({
    url: `/api/books/${item.id}`,
    method: 'delete',
  })
  console.log(`rhj2`, JSON.stringify(res.data.data))
  promptAction.showToast({
    message: res.data.message
  })
  this.getBookList()
} catch (err) {
  console.log(`rhj2`, JSON.stringify(err))
}

5.5 完整代码

bookdata

export interface IBookResult {
  /**
   * 响应数组
   */
  data: IBookInfo[];

  /**
   * 响应消息
   */
  message: string;
}
export interface IBookRes {
  /**
   * 响应数组
   */
  data: IBookInfo;

  /**
   * 响应消息
   */
  message: string;
}



export interface IBookInfo {
  /**
   * 图书作者
   */
  author: string;

  /**
   * 图书名字
   */
  bookname: string;

  /**
   * 图书id
   */
  id: number;

  /**
   * 图书出版社
   */
  publisher: string;

  creator:'xxx' ;
}

BookList

import router from '@ohos.router'
import { IBookInfo, IBookRes, IBookResult } from './BookData'
import { promptAction } from '@kit.ArkUI'
import axios, { AxiosResponse } from '@ohos/axios'

//const req = http.createHttp()
export const req = axios.create({
  baseURL: 'https://hmajax.itheima.net'
})


@Entry
@Component
struct BookList {
  @Watch('getBookList')
  @State bookList: IBookInfo[] = []

  onPageShow(): void {
    this.getBookList()
  }

  async getBookList() {
    try {
      let res: AxiosResponse<IBookResult> = await req.request({
        url: '/api/books',
        method: 'get',
        params: {
          creator: 'xxx'
        }
      })
      this.bookList = res.data.data
    } catch (err) {
      console.log(`rhj`, JSON.stringify(err.message))
    }
  }

  build() {
    Column() {
      this.MyBook()
      if (this.bookList.length == 0) {
        this.loadingBuilder()
      }
      this.BookList()

    }
    .width('100%')
    .height('100%')
  }

  @Builder
  MyBook() {
    Row() {
      Image($r('app.media.ic_public_drawer_filled'))
        .height(20)
      Text('我的书架')
        .fontWeight(700)
      Image($r('app.media.ic_public_add'))
        .height(20)
        .onClick(() => {
          router.pushUrl({
            url: 'pages/books/AddBook',
            params: {}
          })
        })
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceBetween)
    .padding(10)
    .border({ width: { bottom: 2 }, color: { bottom: '#ffd4d4d9' } })
    .margin({ bottom: 10 })
  }

  @Builder
  BookList() {
    List() {
      ForEach(this.bookList, (item: IBookInfo, index: number) => {
        ListItem() {
          Row({ space: 10 }) {
            Image($r('app.media.ic_public_cover'))
              .width(80)
              .height(100)
            Column({ space: 30 }) {
              Column({ space: 5 }) {
                Text('书名:' + item.bookname)
                  .fontSize(20)
                  .fontWeight(800)
                Text('作者:' + item.author)
                  .fontSize(14)
                  .fontColor('#999999')
              }
              .alignItems(HorizontalAlign.Start)

              Text('出版社:' + item.publisher)
                .fontColor('#999999')
                .fontSize(14)
            }
            .layoutWeight(1)
            .alignItems(HorizontalAlign.Start)
          }
          .padding({ left: 10, right: 10, bottom: 10 })
        }
        .swipeAction({ end: this.deleteBook(item) })
        .onClick(() => {
          router.pushUrl({
            url: 'pages/books/EditBook',
            params: { id: item.id, }
          }, router.RouterMode.Single)
        })
      })

    }
  }

  @Builder
  deleteBook(item: IBookInfo) {
    Column() {
      Text('删除')
        .fontSize(20)
        .backgroundColor('#f40')
        .fontColor('#fff')
        .width(60)
        .textAlign(TextAlign.Center)
        .height('100%')
    }
    .padding(10)
    .onClick(() => {
      promptAction.showDialog({
        title: '提示',
        message: `确定要删除${item.bookname}吗`,
        buttons: [{ text: '确认', color: '#367bf6' }, { text: '取消', color: '#000' }]
      })
        .then(async res => {
          if (res.index == 0) {
            try {
              let res: AxiosResponse<IBookRes> = await req.request({
                url: `/api/books/${item.id}`,
                method: 'delete',
              })
              console.log(`rhj2`, JSON.stringify(res.data.data))
              promptAction.showToast({
                message: res.data.message
              })
              this.getBookList()
            } catch (err) {
              console.log(`rhj2`, JSON.stringify(err))
            }
          }
        })
    })
  }

  @Builder
  loadingBuilder() {
    Row() {
      LoadingProgress()
        .height(50)
        .color(Color.Gray)
      Text('正在努力加载~ ~ ~')
    }
  }
}

AddList

import { promptAction, router } from '@kit.ArkUI'
import axios, { AxiosResponse } from '@ohos/axios'
import { IBookInfo, IBookRes } from './BookData'

//const req = http.createHttp()
export const req = axios.create({
  baseURL: 'https://hmajax.itheima.net'
})

@Entry
@Component
struct AddList {
  @State bookname: string = ''
  @State author: string = ''
  @State publisher: string = ''

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

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

        Row() {
          Text('图书出版社:')
            .fontWeight(500)
          TextInput({ placeholder: '请输入图书出版社', text: $$this.publisher })
            .backgroundColor('#fff')
        }
        .border({ width: { bottom: 1 }, color: { bottom: '#ffd4d4d9' } })

        Button('保存')
          .width('100%')
          .type(ButtonType.Normal)
          .borderRadius(10)
          .margin({ top: 30 })
          .onClick(async () => {
            if (this.bookname == '' || this.author == '' || this.publisher == '') {
              promptAction.showToast({
                message: '图书内容不能为空'
              })
              return
            }
            try {
              let res: AxiosResponse<IBookRes> = await req.request<null, AxiosResponse<IBookRes>, IBookInfo>({
                url: '/api/books',
                method: 'post',
                data: {
                  bookname: this.bookname,
                  author: this.author,
                  publisher: this.publisher,
                  creator: 'xxx',
                  id: Date.now()

                }
              })
              promptAction.showToast({
                message: res.data.message
              })
              router.back()
            } catch (err) {
              console.log(`rhj`, JSON.stringify(err))
            }
          })
      }
      .padding(10)

    }
    .width('100%')
    .height('100%')
    .title('新增图书')
    .backButtonIcon($r('app.media.ic_public_arrow_left'))
    .titleMode(NavigationTitleMode.Mini)

  }
}

EditBook

import { IBookInfo, IBookRes } from './BookData'
import router from '@ohos.router'
import { promptAction } from '@kit.ArkUI'
import axios, { AxiosResponse } from '@ohos/axios'

//const req = http.createHttp()
export const req = axios.create({
  baseURL: 'https://hmajax.itheima.net'
})

@Entry
@Component
struct EditBook {
  @State bookname: string = ''
  @State author: string = ''
  @State publisher: string = ''
  @State bookid: number = -1

  async aboutToAppear() {
    const data = router.getParams() as IBookInfo
    this.bookid = data.id
    console.log(`rhj`, this.bookid)
    try {
      let res: AxiosResponse<IBookRes> = await req.request({
        url: `/api/books/${this.bookid}`,
        method: 'get',
      })
      console.log(`rhj1`, JSON.stringify(res.data.data))
      this.bookname = res.data.data.bookname
      this.author = res.data.data.author
      this.publisher = res.data.data.publisher
    } catch (err) {
      console.log(`rhj1`, err)

    }

  }

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

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

        Row() {
          Text('图书出版社:')
            .fontWeight(500)
          TextInput({ placeholder: '请输入图书出版社', text: $$this.publisher })
            .backgroundColor('#fff')
        }
        .border({ width: { bottom: 1 }, color: { bottom: '#ffd4d4d9' } })

        Button('保存')
          .width('100%')
          .type(ButtonType.Normal)
          .borderRadius(10)
          .margin({ top: 30 })
          .onClick(() => {
            promptAction.showDialog({
              message: '确定要修改吗',
              buttons: [{ text: '确认', color: '#367bf6' }, { text: '取消', color: '#000' }]
            })
              .then(async res => {
                if (res.index == 0) {
                  try {
                    let res: AxiosResponse<IBookRes> = await req.request<null, AxiosResponse<IBookRes>, IBookInfo>({
                      url: `api/books/${this.bookid}`,
                      method: 'put',
                      data: {
                        id: this.bookid,
                        bookname: this.bookname,
                        author: this.author,
                        publisher: this.publisher,
                        creator: 'xxx'
                      }
                    })
                    promptAction.showToast({
                      message: res.data.message
                    })
                    router.back()

                  } catch (err) {
                    console.log(``, JSON.stringify(err))

                  }
                  // req.request(`https://hmajax.itheima.net/api/books/${this.bookid}`, {
                  //   method: http.RequestMethod.PUT,
                  //   header: { contentType: 'application/json' },
                  //   extraData: {
                  //     bookname: this.bookname,
                  //     author: this.author,
                  //     publisher: this.publisher,
                  //     creator: 'ivan'
                  //   }
                  // })
                  //   .then(res => {
                  //     let obj: IBookRes = JSON.parse(res.result.toString())
                  //     promptAction.showToast({
                  //       message: obj.message
                  //     })
                  //     router.back()
                  //   })
                }
              })
          })
      }
      .padding(10)
    }
    .width('100%')
    .height('100%')
    .title('编辑图书')
    .backButtonIcon($r('app.media.ic_public_arrow_left'))
    .titleMode(NavigationTitleMode.Mini)
  }
}