跳至主要內容

网络连接

大约 5 分钟

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/net-mgmt-overview-0000001478341009-V2

HTTP数据请求

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/http-request-0000001478061585-V2

应用通过HTTP发起一个数据请求,支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。

HTTP数据请求功能主要由http模块提供。

使用该功能需要申请ohos.permission.INTERNET权限。

权限申请请参考访问控制(权限)开发指导open in new window

涉及的接口如下表,具体的接口说明请参考API文档open in new window

接口名功能描述
createHttp()创建一个http请求。
request()根据URL地址,发起HTTP网络请求。
destroy()中断请求任务。
on(type: 'headersReceive')订阅HTTP Response Header 事件。
off(type: 'headersReceive')取消订阅HTTP Response Header 事件。
once('headersReceive')8+订阅HTTP Response Header 事件,但是只触发一次。

request接口开发步骤

  1. 从@ohos.net.http.d.ts中导入http命名空间。
  2. 调用createHttp()方法,创建一个HttpRequest对象。
  3. 调用该对象的on()方法,订阅http响应头事件,此接口会比request请求先返回。可以根据业务需要订阅此消息。
  4. 调用该对象的request()方法,传入http请求的url地址和可选参数,发起网络请求。
  5. 按照实际业务需要,解析返回结果。
  6. 调用该对象的off()方法,取消订阅http响应头事件。
  7. 当该请求使用完毕时,调用destroy()方法主动销毁。
// 引入包名
import http from '@ohos.net.http';

// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();
// 用于订阅HTTP响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息
// 从API 8开始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。 8+
httpRequest.on('headersReceive', (header) => {
    console.info('header: ' + JSON.stringify(header));
});
httpRequest.request(
    // 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
    "EXAMPLE_URL",
    {
        method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET
        // 开发者根据自身业务需要添加header字段
        header: {
            'Content-Type': 'application/json'
        },
        // 当使用POST请求时此字段用于传递内容
        extraData: {
            "data": "data to send",
        },
        expectDataType: http.HttpDataType.STRING, // 可选,指定返回数据的类型
        usingCache: true, // 可选,默认为true
        priority: 1, // 可选,默认为1
        connectTimeout: 60000, // 可选,默认为60000ms
        readTimeout: 60000, // 可选,默认为60000ms
        usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
    }, (err, data) => {
        if (!err) {
            // data.result为HTTP响应内容,可根据业务需要进行解析
            console.info('Result:' + JSON.stringify(data.result));
            console.info('code:' + JSON.stringify(data.responseCode));
            // data.header为HTTP响应头,可根据业务需要进行解析
            console.info('header:' + JSON.stringify(data.header));
            console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
        } else {
            console.info('error:' + JSON.stringify(err));
            // 取消订阅HTTP响应头事件
            httpRequest.off('headersReceive');
            // 当该请求使用完毕时,调用destroy方法主动销毁
            httpRequest.destroy();
        }
    }
);
image-20240428171812486
image-20240428171812486

案例

现在有这么一个接口: http://127.0.0.1:3000/shops?pageNo=1&&pageSize=4 返回值如下

[
  {
    "id": 1,
    "name": "103茶餐厅",
    "images": [
      "/images/s3fqawWswzk.jpg",
      "/images/aZGOT1OjpJmLxG6urQ.jpg"
    ],
    "area": "大关",
    "address": "金华路锦昌文华苑29号",
    "avgPrice": 80,
    "comments": 3035,
    "score": 37,
    "openHours": "10:00-22:00"
  },
  {
    "id": 2,
    "name": "蔡馬洪涛烤肉·老北京铜锅涮羊肉",
    "images": [
      "/images/faca41195272.jpg",
      "/images/a9f88d706914.jpg",
      "/images/jpJmLxG6urQ.jpg"
    ],
    "area": "拱宸桥/上塘",
    "address": "上塘路1035号(中国工商银行旁)",
    "avgPrice": 85,
    "comments": 1460,
    "score": 46,
    "openHours": "11:30-03:00"
  },
  {
    "id": 3,
    "name": "新白鹿餐厅(运河上街店)",
    "images": [
      "/images/7cgjmzif2w2aalka4gms.jpg",
      "/images/73w0k4d40mxjt54btzda.jpg",
      "/images/uyb31c7yfqy95dejvis1.jpg"
    ],
    "area": "运河上街",
    "address": "台州路2号运河上街购物中心F5",
    "avgPrice": 61,
    "comments": 8045,
    "score": 47,
    "openHours": "10:30-21:00"
  },
  {
    "id": 4,
    "name": "Mamala(杭州远洋乐堤港店)",
    "images": [
      "/images/xpm2bq95a3ro2lc4vp5u.jpg",
      "/images/7kd3rq9hvtougx3mhnlt.jpg"
    ],
    "area": "拱宸桥/上塘",
    "address": "丽水路66号远洋乐堤港商城2期1层B115号",
    "avgPrice": 290,
    "comments": 9529,
    "score": 49,
    "openHours": "11:00-22:00"
  }
]
image-20240428232115572
image-20240428232115572
//src/main/ets/viewmodel/ShopInfo.ts

export default class ShopInfo {
  id: number
  name: string
  images: string[]
  area: string
  address: string
  avgPrice: number
  comments: number
  score: number
  openHours: string
}
// src/main/ets/model/ShopModel.ts

import http from '@ohos.net.http'
import ShopInfo from '../viewmodel/ShopInfo'

class ShopModel {
  pageNo: number = 1
  url: string = `http://127.0.0.1:3000/`

  getShopList(): Promise<ShopInfo[]> {
    return new Promise(
      (resolve, reject) => {
        let httpRequest = http.createHttp()

        httpRequest.request(
          this.url + `shops?pageNo=${this.pageNo}&pageSize=4`,
          {
            method: http.RequestMethod.GET
          }
        )
          .then((res: http.HttpResponse) => {
            if (res.responseCode === 200) {
              // 请求成功
              console.log("Success")
              resolve(JSON.parse(res.result.toString()))
            }
            else {
              console.log("Error", JSON.stringify(res))
              reject("Error")
            }
          })
          .catch((err: Error) => {
            // 请求失败
            console.log("Error", JSON.stringify(err))
            reject("Error")
          })
      }
    )
  }
}

const shopModel = new ShopModel()

export default shopModel as ShopModel
// src/main/ets/views

import ShopInfo from '../viewmodel/ShopInfo'

@Component
export default struct ShopItem {
  shop: ShopInfo

  build(){
    Column({space: 5}){
      Row(){
        Text(this.shop.name)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .ellipsisTextOverFlow()
      }
      .width('100%')

      Row(){
        Text(this.shop.address)
          .fontColor('#a3a3a3')
          .ellipsisTextOverFlow()
      }.width('100%')

      Row({space: 5}){
        Rating({rating: this.shop.score/10 , indicator: true}).stars(5).stepSize(0.1)
        Text(`${this.shop.score / 10}`).fontColor('#ffb04d')
        Text(`${this.shop.comments}`).fontColor('#222')
        Blank()
        Text(`${this.shop.avgPrice}/人`)
      }.width('100%')

      List({space: 10}){
        ForEach(this.shop.images, (image) => {
          ListItem(){
            Column(){
              Image(image)
                .width(150).aspectRatio(1.1).borderRadius(5)
            }
          }
        })
      }
      .listDirection(Axis.Horizontal)
      .width('100%')
    }
    .width('100%')
    .height(240)
    .padding(12)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .shadow({radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4})
  }
}

// 文本超出时的统一样式处理
@Extend(Text)
function ellipsisTextOverFlow(line: number = 1){
  .textOverflow({overflow: TextOverflow.Ellipsis})
  .maxLines(line)
}
// src/main/ets/pages/Index.ets

import ShopInfo from '../viewmodel/ShopInfo'

@Component
export default struct ShopItem {
  shop: ShopInfo

  build(){
    Column({space: 5}){
      Row(){
        Text(this.shop.name)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .ellipsisTextOverFlow()
      }
      .width('100%')

      Row(){
        Text(this.shop.address)
          .fontColor('#a3a3a3')
          .ellipsisTextOverFlow()
      }.width('100%')

      Row({space: 5}){
        Rating({rating: this.shop.score/10 , indicator: true}).stars(5).stepSize(0.1)
        Text(`${this.shop.score / 10}`).fontColor('#ffb04d')
        Text(`${this.shop.comments}`).fontColor('#222')
        Blank()
        Text(`${this.shop.avgPrice}/人`)
      }.width('100%')

      List({space: 10}){
        ForEach(this.shop.images, (image) => {
          ListItem(){
            Column(){
              Image(image)
                .width(150).aspectRatio(1.1).borderRadius(5)
            }
          }
        })
      }
      .listDirection(Axis.Horizontal)
      .width('100%')
    }
    .width('100%')
    .height(240)
    .padding(12)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .shadow({radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4})
  }
}

// 文本超出时的统一样式处理
@Extend(Text)
function ellipsisTextOverFlow(line: number = 1){
  .textOverflow({overflow: TextOverflow.Ellipsis})
  .maxLines(line)
}

第三方库 axios

image-20240429151445521
image-20240429151445521

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/ide-command-line-ohpm-0000001490235312-V2

OHPM CLI 作为鸿蒙生态三方库的包管理工具,支持OpenHarmony共享包的发布、安装和依赖管理。

  1. 下载ohpm工具包,点击链接获取open in new window

  2. 解压文件,进入“ohpm/bin”目录,打开命令行工具,执行如下指令init.bat初始化ohpm

  3. 将ohpm配置到环境变量中。

    • Windows环境变量设置方法:

      此电脑 > 属性 > 高级系统设置 > 高级 > 环境变量中,将ohpm命令行工具的bin目录配置到系统或者用户的PATH变量中。

  4. 安装完成之后,执行ohpm -v 输出版本号即为安装成功

配置完环境变量后可能需要重启电脑才能生效

image-20240429151700246
image-20240429151700246

OpenHarmony三方库中心仓: https://ohpm.openharmony.cn/#/cn/home

以下为 使用案例

// import http from '@ohos.net.http'
import axios from '@ohos/axios'
import ShopInfo from '../viewmodel/ShopInfo'

class ShopModel {
  pageNo: number = 1
  url: string = `http://127.0.0.1:3000/`

  getShopList(): Promise<ShopInfo[]> {
    return new Promise(
      (resolve, reject) => {
        axios.get(
          this.url + `shops?pageNo=${this.pageNo}&pageSize=4`,
        )
          .then((res) => {
            if (res.status === 200) {
              // 请求成功
              console.log("Success")
              resolve(res.data)
            }
            else {
              console.log("Error", JSON.stringify(res))
              reject("Error")
            }
          })
          .catch((err: Error) => {
            // 请求失败
            console.log("Error", JSON.stringify(err))
            reject("Error")
          })
      }
    )
  }
}

const shopModel = new ShopModel()

export default shopModel as ShopModel