了解HTTP请求

HTTP(HyperText Transfer Protocol)请求是指客户端(如浏览器、移动应用等)向服务器发送的一种请求,用于获取资源(如网页、图片、视频等)或与服务器进行交互。

1.1 HTTP请求

HTTP 请求是 Web 通信的基础,通常包含以下几个关键部分:

  1. 请求行(Request Line):

    1. 包含三个部分:HTTP 方法(如 GET、POST、PUT、DELETE 等)、请求的资源路径(URL)和 HTTP 版本(如 HTTP/1.1)。

    2. 例如:GET /index.html HTTP/1.1

  2. 请求头(Request Headers):

    1. 包含键值对,提供了请求的附加信息,如客户端类型、认证信息、缓存控制等。

    2. 例如:

    3. textCopy Code

    4. Host: www.example.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

  3. 空行(CRLF):

    1. 请求头和请求体之间必须有一个空行,这是通过回车(CR)和换行(LF)字符表示的。
  4. 请求体(Request Body):

    1. 并非所有请求都包含请求体,主要用于 POST、PUT 等方法,包含了要发送给服务器的数据。

    2. 例如,一个 POST 请求的体可能包含表单数据或 JSON 对象:

    3. textCopy Code

    4. { "username": "example", "password": "password123" }

1.2 常见的 HTTP 方法

  • GET:请求从服务器获取资源。

  • POST:向服务器发送数据,通常用于提交表单或上传文件。

  • PUT:向服务器上传其应在目标资源位置存储的资源的全部内容。

  • DELETE:请求服务器删除指定的资源。

  • HEAD:请求获取与 GET 请求相同的响应,但不返回响应体。

  • OPTIONS:请求描述目标资源的通信选项,通常用于检查服务器支持的 HTTP 方法。

  • PATCH:请求对资源进行部分修改。

1.3 HTTP 响应

服务器接收到 HTTP 请求后,会返回一个 HTTP 响应,包含:

  1. 状态行(Status Line):

    1. 包含 HTTP 版本、状态码(如 200、404)和状态消息(如 OK、Not Found)。

    2. 例如:HTTP/1.1 200 OK

  2. 响应头(Response Headers):

    1. 与请求头类似,包含键值对,提供响应的附加信息,如内容类型、服务器类型、缓存控制等。
  3. 空行(CRLF):

    1. 响应头和响应体之间必须有一个空行。
  4. 响应体(Response Body):

    1. 包含服务器返回的实际数据,如 HTML 文档、JSON 对象、图片等。

通过理解 HTTP 请求和响应的结构,您可以更好地进行 Web 开发、调试和性能优化

实现HTTP请求

2.1 官网文档:

【指南】 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/http-request-V5

【API参考】 https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-http-V5

2.2 导入模块

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

import { http } from '@kit.NetworkKit';

2.3 申请网络权限

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

【entry】【src】【main】【module.json5】

{
  "module": {
    "requestPermissions": [{
      //设置申请网络权限
      "name": "ohos.permission.INTERNET"
    }],
    ...
    }
  }

2.4 request接口开发步骤

  1. 从@kit.NetworkKit中导入http命名空间。

  2. 调用createHttp()方法,创建一个HttpRequest对象。

  3. 调用该对象的on()方法,订阅http响应头事件,此接口会比request请求先返回。可以根据业务需要订阅此消息。

  4. 调用该对象的request()方法,传入http请求的url地址和可选参数,发起网络请求。

  5. 按照实际业务需要,解析返回结果。

  6. 调用该对象的off()方法,取消订阅http响应头事件。

  7. 当该请求使用完毕时,调用destroy()方法主动销毁。

2.5 官网核心代码

![[65dc3b8a-f1bc-4b04-a0f2-0f377023c1ec.png]]

// 引入包名
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();

// 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
httpRequest.request(
  "https://m.taoyuewenhua.com/ajax/book_mall?ctype=1&seed=2580&page=0",
  {
    // 可选,默认为http.RequestMethod.GET
    //  http.RequestMethod.POST
    method: http.RequestMethod.GET,
    // 开发者根据自身业务需要添加header字段
    // 下面配置表示接收服务器端传来的json数据
    header: { 'Accept': 'application/json' },
    // 读取超时时间,可选,默认为60000ms
    readTimeout: 60000,
    // 连接超时时间,可选,默认为60000ms
    connectTimeout: 60000,
  },
  // 遵循错误优先原则
  (err: BusinessError, data: http.HttpResponse) => {
    if (!err) {
      // data.result为HTTP响应内容,可根据业务需要进行解析
      console.info('Result:' + JSON.stringify(data.result));
      console.info('code:' + JSON.stringify(data.responseCode));
      // 当该请求使用完毕时,开发者务必调用destroy方法主动销毁该JavaScript Object请求对象。
      httpRequest.destroy();
    } else {
      //请求发生错误时的业务处理
      console.info('error:' + JSON.stringify(err));
      // 当该请求使用完毕时,开发者务必调用destroy方法主动销毁该JavaScript Object。
      httpRequest.destroy();
    }
  });

@Entry
@Component
struct Index {
  build() {

  }
}

2.6 请求淘小说数据

import { http } from '@kit.NetworkKit'

class ResponseResult {
  errcode: number;
  errmsg: string | Resource;
  data: string | Object | ArrayBuffer;

  constructor() {
    this.errcode = 0;
    this.errmsg = '';
    this.data = '';
  }
}

// bookList数据类型
interface  BookItemModel{
  title:string,
  intro:string,
  authorName:string,
  coverUrl:string
}

// channelList 数据类型
interface ChannelItemModel {
  mcid:number,
  title: string,
  bookList:BookItemModel[]
}

interface DataModel {
  channelList: ChannelItemModel[],
  // bannerList: ChannelItemModel[]
}

@Entry
@Component
struct Test {
  @State homeData: DataModel = {
    channelList: [],
    bannerList: []
  }

  build() {
    Column() {
      Button("获取淘小说数据")
        .onClick(() => {
          // 实例化出来了一个对象格式{errorCode:"",errorMsg:"",data:""}
          let serverData = new ResponseResult()
          let httpRequest = http.createHttp()
          httpRequest.request("https://m.taoyuewenhua.com/ajax/book_mall?ctype=1&seed=4724&page=0", {
            method: http.RequestMethod.GET,
            header: {
              "Content-type": "application/json"
            }
          }, (err, value: http.HttpResponse) => {
            if (!err) {
              // ----------------------------------------------------------官网代码
               // 因为value.result是字符串,但TS不能推理出类型,所以要显示转换为string类型,处理方法用两种
               // 第一种
              let result = `${value.result}`
              let resultJSON: ResponseResult = JSON.parse(result)
              // 第二种
              // let resultJSON: ResponseResult = JSON.parse(value.result as string)
              
              serverData.data = resultJSON.data
              serverData.errcode = resultJSON.errcode
              serverData.errmsg = resultJSON.errmsg
              // console.log(typeof serverData)  // object类型  {"channelList}
              this.homeData = serverData.data as DataModel
              
              //-----------------------------------------------------------精简代码
              //  let result = `${value.result}`
              //    serverData = JSON.parse(result)
              //    this.homeData = serverData.data as DataModel
            } else {
              console.log(JSON.stringify(err))
            }
          })
        })

      ForEach(this.homeData.channelList, (item: ChannelItemModel) => {
        Row() {
          Text(item.title)
        }.width('90%').height(50).margin(10).backgroundColor(Color.White)
            // 嵌套渲染bookList数据
            ForEach(item.bookList,(books:BookItemModel)=>{
              Column(){
                Text(books.title)
                Text(books.authorName)
                Text(books.intro)
                Text(books.coverUrl)
              }
            })
      }, (item: ChannelItemModel) => item.title)

    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Gray)
  }
}

支持Promise请求的API

![[c01db55e-a786-4f2e-9924-3e20da54aefc.png]]

示例代码1:

import { http } from '@kit.NetworkKit';

class Header {
  public contentType: string;

  constructor(contentType: string) {
    this.contentType = contentType;
  }
}

let httpRequest = http.createHttp();
let promise = httpRequest.request("EXAMPLE_URL", {
  method: http.RequestMethod.GET,
  connectTimeout: 60000,
  readTimeout: 60000,
  header: new Header('application/json')
});
promise.then((data:http.HttpResponse) => {
  console.info('Result:' + data.result);
  console.info('code:' + data.responseCode);
}).catch((err:Error) => {
  console.info('error:' + JSON.stringify(err));
});

示例代码2

homeDataModel.ets

import { http } from "@kit.NetworkKit";
import { CommonConstants as Const } from '../common/CommonConstants'

export interface BannerItemModel {
  mbid: number,
  title: string
}

export interface ChannelItemModel {
  mbid: number,
  title: string,
  bookCount: number
}

export interface PageDataModel {
  bannerList: BannerItemModel[],
  channelList: ChannelItemModel[]
}

export interface  ErrorCase {
  errCode: number
  msg: string
}

export function httpRequestGet(): Promise<PageDataModel> {
  return new Promise((resolve, reject) => {
    let httpRequest = http.createHttp();
    let promise = httpRequest.request("https://m.taoyuewenhua.com/ajax/book_mall?ctype=1&seed=7942&page=0", {
      method: http.RequestMethod.GET,
      connectTimeout: 60000,
      readTimeout: 60000,
      header: {
        "content-type": 'application/json',
        "user-agent": Const.USER_AGENT
      }
    });

    promise
      .then((value: http.HttpResponse) => {
        // console.info('Result:' + data.result);
        // console.info('code:' + data.responseCode);

        //处理HTTP状态码,200表求请求成功
        if (value.responseCode === 200) {
          //请求成功
          resolve(JSON.parse(value.result as string).data)

        } else {
          //请求失败
           reject({
             errCode: 1,
             msg: '网络连接错误'
           })
        }
      })
      .catch((err: Error) => {
        console.info('error:' + JSON.stringify(err));
      });
  })
}

MyHttp.ets

import { http } from '@kit.NetworkKit';
import { BannerItemModel, ErrorCase, httpRequestGet, PageDataModel } from '../model/homeDataModel';

@Entry
@Component
struct MyHttp {
  @State homeData: PageDataModel = {
    bannerList: [],
    channelList: []
  }
  @State isSuccessRequest: boolean = true

  //组件初始化
  aboutToAppear(): void {
    this.getData()
  }

  //获取数据
  getData() {
    httpRequestGet()
      .then((data: PageDataModel) => {
          this.homeData = data
      }).catch((err: ErrorCase)=>{
        if (err.errCode === 1){
          this.isSuccessRequest = false
        }
    })
  }

  build() {
    Column() {
      if (!this.isSuccessRequest) {
        // 网络错误
        Text("网络连接错误")
      } else {
        //列表显示
        Text("商品列表")
        Column() {
          ForEach(this.homeData.bannerList, (item: BannerItemModel) => {
            Row() {
              Text(item.title)
            }
          }, (item: BannerItemModel) => item.title)
        }

      }
    }
  }
}
  1. 两个深入理解Promise的案例

  2. 案例1

function ajax(): Promise<string>{
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      //拿到了接口数据
      let data1 = '结果'
      resolve(data1)
    },1000)
  })
}

function task(): Promise<string>{
  //第一种方案
  return new Promise((resolve,reject)=>{
    ajax()
      .then((data: string)=>{
        console.log('拿到了ajax的结果',data)
        resolve(data)
      })
  })
}
function handleData(){
  // 通过调用task拿到"结果"
  task().then((data: string)=>{
    console.log('终于拿到了',data)
  })
}
handleData()

@Entry
@Component
struct Test {
  build() {

  }
}
  1. 案例2

function ajax(): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      //拿到了接口数据
      let data1 = '结果'
      resolve(data1)
    }, 1000)
  })
}

function task() {
  //return了promise
  return ajax().then((data: string) => {
    console.log('拿到了ajax的结果', data)
    return data
  })
}

function handleData() {
  task().then((data)=>{
    console.log('拿到了最终的结果',data)
  })
}

handleData()

@Entry
@Component
struct Test {
  build() {

  }
}

新闻发布案例

1. Codelabs地址

https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_NEXT-NewsRelease

![[11cb3ee7-07b9-4081-82aa-6ce2c4dab130.png]]

源码下载和分析

1. gitee地址下载源码

https://gitee.com/harmonyos_codelabs/NewsRelease

![[cb199603-9952-4a23-ada3-c463327227a5.png]]

  1. 常量和枚举

export default class Constants {
  static readonly SERVER: string = 'http://xxx.xxx.xxx.xxx:9588';
  static readonly GET_NEWS_TYPE: string = 'news/getNewsType';
  static readonly GET_NEWS_LIST: string = 'news/getNewsList';
  static readonly UPLOAD_NEWS: string = 'news/addNews';
  static readonly UPLOAD_FILE: string = '/files/upload';
  static readonly IMAGE_PREFIX: string = '/images/';
  static readonly NEWS_EDIT_PAGE: string = 'pages/NewsEditPage'
  static readonly SERVER_CODE_SUCCESS: string = 'success';
  static readonly Y_OFF_SET_COEFFICIENT: number = 0.1;
  static readonly PAGE_SIZE: number = 10;
  static readonly CUSTOM_LAYOUT_HEIGHT: number = 70;
  static readonly GET_TAB_DATA_CURRENT_PAGE: number = 1;
  static readonly HTTP_CODE_200: number = 200;
  static readonly DELAY_ANIMATION_DURATION: number = 300;
  static readonly DELAY_TIME: number = 1000;
  static readonly ANIMATION_DURATION: number = 2000;
  static readonly HTTP_READ_TIMEOUT: number = 10000;
  static readonly CONTENT_MAX_LINE: number = 3;
  static readonly LIST_SPACE: number = 12;
  static readonly ITEM_IMG_SPACE: number = 8;
  static readonly TYPE_FONT_WEIGHT: number = 700;
  static readonly TITLE_FONT_WEIGHT: number = 500;
  static readonly DESC_FONT_WEIGHT: number = 400;
  static readonly TYPE_ASPECT_RATIO: number = 2;
  static readonly DESC_OPACITY: number = 0.6;
  static readonly FULL_PERCENT: string = '100%';
  static readonly DIVIDER_WIDTH: string = '90%';
  static readonly RELEASE_TITLE: string = '新闻发布';
}


export const enum RefreshConstant {
  DELAY_PULL_DOWN_REFRESH = 50,
  CLOSE_PULL_DOWN_REFRESH_TIME = 150,
  DELAY_SHRINK_ANIMATION_TIME = 500
}

export const enum RefreshState {
  DropDown = 0,
  Release = 1,
  Refreshing = 2,
  Success = 3,
  Fail = 4
}

export const enum PageState {
  Loading = 0,
  Success = 1,
  Fail = 2
}


export const enum UploadingState {
  COMPLETE = 'complete',
  FAIL = 'fail'
}


export const enum RequestMethod {
  POST = 'POST',
  GET = 'GET'
}


export const enum ContentType {
  JSON = 'application/json',
  FORM = 'multipart/form-data'
}
  1. 数据类型和http通用请求封装

import { http } from '@kit.NetworkKit';

export default class ResponseResult {
  code: string;
  msg: string | Resource;
  data: string | Object | ArrayBuffer;

  constructor() {
    this.code = '';
    this.msg = '';
    this.data = '';
  }
}


export class NewsData {
  title: string = '';
  content: string = '';
  imagesUrl: Array<NewsFile> = [new NewsFile()];
  source: string = '';
}

export class NewsFile {
 
  id: number = 0;
  url:  | Object | ArrayBuffer = '';
  type: number = 0;
  newsId: number = 0;
}


export function httpRequestGet(url: string) {
  return httpRequest(url, http.RequestMethod.GET);
}

export function httpRequestPost(url: string, newsData: NewsData) {
  return httpRequest(url, http.RequestMethod.POST, newsData);
}

function httpRequest(url: string, method: http.RequestMethod, params?: NewsData): Promise<ResponseResult> {
  let httpRequest = http.createHttp();
  let responseResult = httpRequest.request(url, {
    method: method,
    readTimeout: Constants.HTTP_READ_TIMEOUT,
    header: {
      'Content-Type': ContentType.JSON
    },
    connectTimeout: Constants.HTTP_READ_TIMEOUT,
    extraData: params
  });
  let serverData = new ResponseResult();
  // Processes the data and returns.
  return responseResult.then((value: http.HttpResponse) => {
    if (value.responseCode === Constants.HTTP_CODE_200) {
      // Obtains the returned data.
      let result = `${value.result}`;
      let resultJson: ResponseResult = JSON.parse(result);
      if (resultJson.code === Constants.SERVER_CODE_SUCCESS) {
        serverData.data = resultJson.data;
      }
      serverData.code = resultJson.code;
      serverData.msg = resultJson.msg;
    } else {
      serverData.msg = `${$r('app.string.http_error_message')}&${value.responseCode}`;
    }
    return serverData;
  }).catch(() => {
    serverData.msg = $r('app.string.http_error_message');
    return serverData;
  });
}
  1. 业务模块请求封装

import NewsTypeBean from './NewsTypeModel'
import ResponseResult from './ResponseResult';
import Constants from '../common/constants/Constants';
import { httpRequestGet } from '../common/utils/HttpUtil';

const DEFAULT_NEWS_TYPES: NewsTypeBean[] = [
  new NewsTypeBean(0, $r('app.string.tab_all')),
  new NewsTypeBean(1, $r('app.string.tab_domestic')),
  new NewsTypeBean(2, $r('app.string.tab_international')),
  new NewsTypeBean(3, $r('app.string.tab_fun')),
  new NewsTypeBean(4, $r('app.string.tab_military')),
  new NewsTypeBean(5, $r('app.string.tab_sports')),
  new NewsTypeBean(6, $r('app.string.tab_science'))
];

class NewsTypeViewModel {
  /**
   * Get news type list from server.
   *
   * @return NewsTypeBean[] newsTypeList
   */
  getNewsTypeList(): Promise<NewsTypeBean[]> {
    return new Promise((resolve: Function) => {
      let url = `${Constants.SERVER}/${Constants.GET_NEWS_TYPE}`;
      httpRequestGet(url).then((data: ResponseResult) => {
        if (data.code === Constants.SERVER_CODE_SUCCESS) {
          resolve(data.data);
        } else {
          resolve(DEFAULT_NEWS_TYPES);
        }
      }).catch(() => {
        resolve(DEFAULT_NEWS_TYPES);
      });
    });
  }

  /**
   * Get default news type list.
   *
   * @return NewsTypeBean[] newsTypeList
   */
  getDefaultTypeList(): NewsTypeBean[] {
    return DEFAULT_NEWS_TYPES;
  }
}

let newsTypeViewModel = new NewsTypeViewModel();

export default newsTypeViewModel as NewsTypeViewModel;
  1. 页面中调用请求获取接口数据

@Entry
@Component
struct MainPage {
  @State tabBarArray: NewsTypeBean[] = NewsTypeViewModel.getDefaultTypeList();
  @State currentIndex: number = 0;

  @Builder TabBuilder(index: number) {
    Column() {
      Text(this.tabBarArray[index].name)
        .height(Constants.FULL_PERCENT)
        .fontSize(this.currentIndex === index ? $r('app.float.bar_selected_font') : $r('app.float.bar_normal_font'))
        .fontWeight(this.currentIndex === index ? Constants.TYPE_FONT_WEIGHT : Constants.DESC_FONT_WEIGHT)
        .fontColor($r('app.color.title_color'))
    }
    .padding({ left: $r('app.float.normal_padding'), right: $r('app.float.normal_padding') })
    .margin({
      left: index === 0 ? $r('app.float.common_padding') : 0,
      right: index === this.tabBarArray.length - 1 ? $r('app.float.common_padding') : 0
    })
  }

  aboutToAppear() {
    // Request news category.
    NewsTypeViewModel.getNewsTypeList().then((typeList: NewsTypeBean[]) => {
      this.tabBarArray = typeList;
    });
  }

部署新闻发布功能的后端服务

  1. 在源码中找到HttpServerOfNews文件夹

![[9aceea57-effd-4233-9a8d-6c72ee4846dc.png]]

  1. 把文件夹移动到一个合法的目录中(路径中没有中文或特殊字符)

  2. 右键,选择用DevEco Studio打开

![[db4371c6-9ff3-481f-b0ec-194b49124522.png]]

  1. 打开终端

![[aeeeb4c8-9334-4267-a633-8337f9ec4b75.png]]

  1. 查看是否安装node

在命令行输入 node -v, 如果显示版本号,则已经安装,如果没有,自行安装

node -v 

![[4bcd51ae-d36e-4d69-a35d-bb3554541797.png]]、

  1. 安装项目依赖
npm i   // 会按package.json的依赖列表进行安装
  1. 运行项目
npm start  // 运行项目

![[10ccd681-e920-4baf-8db3-ae5f385d3484.png]]

  1. 在鸿蒙项目中修改以下代码:
// 修改前
static readonly SERVER: string = 'http://XXXXXXX:9588';

//修改后
static readonly SERVER: string = 'http://localhost:9588';

![[aaff72ba-edda-45a8-8ec5-5457fb7f2346.png]]

课前测

需求:

  1. 封装公共网络请求 (函数 httpRequest)

  2. 分别封装GET和POST网络请求 (函数 httpRequestGet 和 httpRequestPost)

  3. 在页面中请求淘小说接口数据

  4. 用LazyForEach实现bannerList数据的懒加载

  5. 只能参考官方文档

homeDataModel.ets

import { http } from "@kit.NetworkKit";
import { CommonConstants as Const } from '../common/CommonConstants'

export interface BannerItemModel {
  mbid: number,
  title: string
}

export interface ChannelItemModel {
  mbid: number,
  title: string,
  bookCount: number
}


export interface PageDataModel {
  bannerList: BannerItemModel[],
  channelList: ChannelItemModel[]
}

export interface responseResult {
  errcode: number,
  errmsg: string,
  data: PageDataModel

}

export interface  ErrorCase {
  errCode: number
  msg: string
}

export function httpRequestGet(url:string){
  return httpRequest(url, http.RequestMethod.GET)
}

export function httpRequestPost(url:string, params?: string){
  return httpRequest(url, http.RequestMethod.POST,params )
}

//在get和post请求时都要复用的代码
export function httpRequest(url: string,method: http.RequestMethod, params?: string): Promise<responseResult> {
  return new Promise((resolve, reject) => {
    let httpRequest = http.createHttp();
    let promise = httpRequest.request(url, {
      method: method,
      connectTimeout: 60000,
      readTimeout: 60000,
      header: {
        "content-type": 'application/json',
        "user-agent": Const.USER_AGENT
      },
      extraData: params
    });

    promise
      .then((value: http.HttpResponse) => {
        //处理HTTP状态码,200表求请求成功
        if (value.responseCode === 200) {
          //请求成功
          resolve(JSON.parse(value.result as string))
        } else {
          reject("错误")
        }
      })
      .catch((err: Error) => {
        console.info('error:' + JSON.stringify(err));
      });
  })
}

BasicDataSource.ets

export class BasicDataSource<T> implements IDataSource {
  private listeners: DataChangeListener[] = [];
  private originDataArray: T[] = [];

  public totalCount(): number {
    return 0;
  }

  public getData(index: number): T {
    return this.originDataArray[index];
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      console.info('add listener');
      this.listeners.push(listener);
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      console.info('remove listener');
      this.listeners.splice(pos, 1);
    }
  }

  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    })
  }

  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    })
  }

  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChange(index);
    })
  }

  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index);
    })
  }

  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
    })
  }

  notifyDatasetChange(operations: DataOperation[]): void {
    this.listeners.forEach(listener => {
      listener.onDatasetChange(operations);
    })
  }
}

MyDataSource.ets

import { BasicDataSource } from './BasicDataSource';
import { BannerItemModel } from './homeDataModel';

export class MyDataSource extends BasicDataSource<BannerItemModel> {
  private dataArray: BannerItemModel[] = [];

  public totalCount(): number {
    return this.dataArray.length;
  }

  public getData(index: number): BannerItemModel {
    return this.dataArray[index];
  }

  public pushData(data: BannerItemModel): void {
    this.dataArray.push(data);
    this.notifyDataAdd(this.dataArray.length - 1);
  }
}

MyHttp.ets

import { BannerItemModel, ErrorCase, httpRequestGet, PageDataModel, responseResult } from '../model/homeDataModel';
import { MyDataSource } from '../model/MyDataSource';

@Entry
@Component
struct MyHttp {
  @State homeData: PageDataModel = {
    bannerList: [],
    channelList: []
  }
  private lazyHomeData: MyDataSource = new MyDataSource()

  //组件初始化
  aboutToAppear(): void {
    this.getData()
  }

  //获取数据
  getData() {
    let url = "https://m.taoyuewenhua.com/ajax/book_mall?ctype=1&seed=200&page=0"
    httpRequestGet(url)
      .then((data: responseResult) => {
        this.homeData = data.data
        for (let item of this.homeData.bannerList){
          this.lazyHomeData.pushData(item)
        }
      })
      .catch((err: ErrorCase) => {
        console.log(err.msg)
      })
  }

  build() {
    Column() {
      //列表显示
      Text("商品列表")
      List() {
        LazyForEach(this.lazyHomeData, (item: BannerItemModel) => {
          ListItem() {
            Text(item.title)
          }
        }, (item: BannerItemModel) => item.title)
      }
    }
  }
}

用函数重载优化请求

ets > common > utils > HttpUtil.ets

import { http } from '@kit.NetworkKit';
import ResponseResult from '../../viewmodel/ResponseResult';
import Constants,{ ContentType} from '../constants/Constants';

//get请求
export function httpRequestGet(url: string) {
  return httpRequest(url, http.RequestMethod.GET);
}
// post请求
export function httpRequestPost<T>(url: string, params?: T) {
  return httpRequest<T>(url, http.RequestMethod.POST, params);
}
// http请求
function httpRequest(url: string, method: http.RequestMethod): Promise<ResponseResult>
function httpRequest<T>(url: string, method: http.RequestMethod,params?: T): Promise<ResponseResult>
function httpRequest<T>(url: string, method: http.RequestMethod,params?: T): Promise<ResponseResult> {
  let httpRequest = http.createHttp();
  let responseResult = httpRequest.request(url, {
    method: method,
    readTimeout: Constants.HTTP_READ_TIMEOUT,
    header: {
      'Content-Type': ContentType.JSON
    },
    connectTimeout: Constants.HTTP_READ_TIMEOUT,
    extraData: params
  });
  let serverData = new ResponseResult();

  return responseResult.then((value: http.HttpResponse) => {
    if (value.responseCode === Constants.HTTP_CODE_200) {
      // Obtains the returned data.
      let result = `${value.result}`;
      let resultJson: ResponseResult = JSON.parse(result);
      if (resultJson.errcode === Constants.SERVER_CODE_SUCCESS) {
        serverData.data = resultJson.data;
      }
      serverData.errcode = resultJson.errcode;
      serverData.errmsg = resultJson.errmsg;
    } else {
      serverData.errmsg = `${$r('app.string.http_error_message')}&${value.responseCode}`;
    }
    return serverData;
  }).catch(() => {
    serverData.errmsg = $r('app.string.http_error_message');
    return serverData;
  });
}
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐