积分582 / 贡献0

提问0答案被采纳0文章52

[经验分享] OpenHarmony_Http连接 原创

Laval社区小助手 显示全部楼层 发表于 2023-12-26 15:21:38

详情:OpenHarmony_Http连接

概述

在OpenHarmony中,Http数据请求功能主要由ohos.net.http模块提供。使用该功能需要申请ohos.permission.INTERNET权限。

Http接口简单介绍

模块/类 函数/方法 功能说明
ohos.net.http function createHttp(): HttpRequest 创建一个HttpRequest对象,该对象涵盖了发起/中断请求、订阅/取消Http响应头 事件等功能。每一个HttpRequest对象对应一个Http请求。如需发起多个Http请求,须为每个Http请求创建对应HttpRequest对象
ohos.net.http.HttpRequest on(type: "headersReceive", callback: AsyncCallback): void 用于订阅http响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息。以callback方式进行异步回调
ohos.net.http.HttpRequest once(type: "headersReceive", callback: Callback): void 用于订阅http响应头,但是只触发一次。一旦触发之后,订阅就会被移除。以callback方式进行异步回调
ohos.net.http.HttpRequest off(type: "headersReceive", callback: Callback): void 取消对http响应头的监听。以callback方式进行异步回调
ohos.net.http.HttpRequest request(url: string, options: HttpRequestOptions, callback: AsyncCallback): void 根据URL地址,发起一个GET请求。以callback方式进行异步回调
ohos.net.http.HttpRequest request(url: string, options: HttpRequestOptions, callback: AsyncCallback): void 根据URL地址,采用不同方式(GET、POST等)发送请求,options中携带请求参数。以callback方式进行异步回调
ohos.net.http.HttpRequest request(url: string, options?: HttpRequestOptions: Promise 根据URL地址,采用不同方式(GET、POST等)发送请求,options中携带请求参数(可选)。以Promise方式进行异步回调

开发步骤

  • 导入@ohos.net.http模块。
  • 创建HttpRequest对象。
  • (可选)订阅HTTP响应头。
  • 根据URL地址,设置请求参数,发起HTTP网络请求。
  • (可选)处理HTTP响应头和HTTP网络请求的返回结果。

Http连接示例

目标

使用http模块相关接口实现向服务端发送GET、POST、PUT、DELETE四种方式的请求

开发环境

示例开发环境:

IDE:DevEco Studio 3.0 Release(build:3.0.0.993)
SDK:Api Version9
开发模型:Stage

具体实现

创建工程

打开DevEco Studio,创建SDK版本为API9、模型为Stage的OpenHarmony项目。

工程目录结构如下:

配置权限

在工程中的module.json5文件中配置ohos.permission.INTERNET 权限。

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

包装Http接口

在ets/service 目录下创建HttpService.ets文件。为了方便在UI页面中调用http模块相关功能,在该文件中创建HttpService类对Http模块相关接口进行封装。

HttService.ets:

import http from '@ohos.net.http';
import Logger from '../util/Logger'

const TAG="HttpDemo"

export class HttpService{
  /**
   * HttpRequest对象,承担了发起/取消、订阅响应事件的职责
   */
  private httpClient:http.HttpRequest;


  private requestMethodMap={
     "GET":http.RequestMethod.GET,
     "POST":http.RequestMethod.POST,
     "PUT":http.RequestMethod.PUT,
     "DELETE":http.RequestMethod.DELETE
  }

  constructor(){
     this.createHttpRequest();
     this.onHeaderReceive();
  }

  /**
   * 创建HttpRequest对象,并赋值给httpClient
   */
  private  createHttpRequest(){
     Logger.info(TAG,"start create HttpRequest");
     this.httpClient=http.createHttp();
     Logger.info(TAG,"create HttpRequest sucess ");
   }


  /**
   * 销毁http连接,中断数据请求
   */
  public destroy(){
     this.httpClient.destroy();
     Logger.info(TAG,"HttpRequest destroyed")
  }

  /**
   * 用于订阅http响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息
    * 从API 8开始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)
   */
  private onHeaderReceive(){
      this.httpClient.on("headersReceive",(data)=>{
          Logger.info(TAG,"ResponseHeader:"+JSON.stringify(data));
      })
  }


  /**
   * 根据url和请求参数,向服务端发送http请求
   * @param url
   * @param param
   */
  public requestHttp(url:string,param:RequestParam){
  
    Logger.info(TAG,"start request:"+JSON.stringify(param));

    let requestOption = {
      method: this.requestMethodMap[param.method],
      extraData: param.extraData,
      header: param.header,
      readTimeout: param.readTimeout,
      connectTimeout: param.connectTimeout
    }

    Logger.info(TAG, "the request param is:" + JSON.stringify(requestOption));
    this.httpClient.request(url,requestOption)
      .then((httpResponse) => {
        Logger.info(TAG, "send request sucess,the response is:" + JSON.stringify(httpResponse));
      })
      .catch((e) => {
        Logger.info(TAG, "send request fail,the err is:" + JSON.stringify(e));
      })
  }


}

/**
 * 请求参数接口
 */
export interface RequestParam {

  method: string;

  extraData?: string | Object | ArrayBuffer;

  header?: Object; // default is 'content-type': 'application/json'

  readTimeout?: number; // default is 60s

  connectTimeout?: number; // default is 60s.
}

let httpService:HttpService=new HttpService();
export default httpService

定义对话框组件

在ets/component目录下创建ReqParamDialog.ets文件,在该文件中定义用于设置请求参数的对话框。 完整代码如下:


@CustomDialog
@Component
export struct ReqParamDialog {
  @State
  list: number[] = [0];
  flag: number = 0;
  keys: string[] = [];
  values: string[] = [];
  setParamCallback: (keys: string[], values: string[]) => void;
  dialogController: CustomDialogController;

  build() {
    Column() {
      ForEach(this.list, (num) => {
        Row() {
          TextInput({ placeholder: "KEY:" })
            .width(120)
            .height(50)
            .onChange((key) => {
              this.keys[this.flag] = key;
            })
          Text(":")
            .width(10)
            .fontSize(16)
            .fontColor(Color.Blue)
            .textAlign(TextAlign.Center)
          TextInput({ placeholder: "VALUE:" })
            .height(50)
            .onChange((value) => {
              this.values[this.flag] = value;
            })
        }
      }, num => num.toString())
      Row() {
        Button("新增")
          .fontSize(25)
          .onClick(() => {
            this.flag++;
            this.list.push(this.flag);
          })
        Button("减少")
          .fontSize(25)
          .onClick(() => {
            if (this.list.length == 1) {
              return;
            }
            this.list.splice(this.list.length - 1, 1);
          })
        Button("确认")
          .fontSize(25)
          .onClick(() => {
            this.setParamCallback(this.keys, this.values);
            this.dialogController.close();
          })

        Button("取消")
          .fontSize(25)
          .onClick(() => {
            this.dialogController.close();
          })
      }

    }
  }
}

效果如下:

定义Http请求组件

在ets/component目录下创建HttpRequest.ets文件,在该文件中绘制http请求的UI界面。

  • 定义选择http请求方法的菜单组件
...
...
@Component
export struct HttpRequest{
  methods:string[]=["GET","POST","PUT","DELETE"];
  ...
  ...
  @Builder
  requestMethod() {
    Flex({direction:FlexDirection.Column}) {
      ForEach(this.methods,(method)=>{
        Column(){
          Text(method)
            .fontSize(20)
            .margin({bottom:1})
            .onClick(()=>{
              this.selectedMethod=method;
            })
        }
      },method=>method)
    }
  }
  ...
  ...
}
  • 组合菜单组件和对话框

将菜单组件绑定到显示请求方法的Text组件上。

build() {
     ...
        Text(this.selectedMethod)//显示选择的Http请求方法
          ...
          .bindMenu(this.requestMethod())
     ...
  }

在HttpRequest组件中创建CustomDialogController对象,并将自定义对话框作为参数传入。

import httpService,{RequestParam} from '../service/HttpService'
import {ReqParamDialog} from '../component/ReqParamDialog'

@Component
export struct HttpRequest{
  ...
  ...
 dialogController: CustomDialogController = new CustomDialogController({builder: ReqParamDialog({setParamCallback:this.setParamCallback.bind(this)}), autoCancel: true, alignment: DialogAlignment.Center })
 ...
 ...
  }
  build() {
     ...
     ...
  }
 ...
}

HttpRequest.ets文件完整代码:

import httpService,{RequestParam} from '../service/HttpService'
import {ReqParamDialog} from '../component/ReqParamDialog'

@Component
export struct HttpRequest{
  /**
   * http请求方法的一个数组,用于生成选择菜单
   */
  methods:string[]=["GET","POST","PUT","DELETE"];
  /**
   * 请求方法,默认为GET
   */
  @State
  selectedMethod:string="GET";
  /**
   * 请求地址,默认为 http://reqres.in/api/users?page=2
   */
  url:string="http://reqres.in/api/users?page=2";
  /**
   * 请求参数
   */
  requestParam:RequestParam=null;
  /**
   * 创建CustomDialogController,传入自定义对话框,控制对话框的显示和关闭
   */
  dialogController: CustomDialogController = new CustomDialogController({builder: ReqParamDialog({setParamCallback:this.setParamCallback.bind(this)}), autoCancel: true, alignment: DialogAlignment.Center })

  @Builder
  requestMethod() {
    Flex({direction:FlexDirection.Column}) {
      ForEach(this.methods,(method)=>{
        Column(){
          Text(method)
            .fontSize(20)
            .margin({bottom:1})
            .onClick(()=>{
              this.selectedMethod=method;
            })
        }
      },method=>method)
    }
    
  }
  build() {
      Column() {
        Row(){
          Text(this.selectedMethod)
            .fontSize(25)
            .align(Alignment.Center)
            .border({width:1})
            .bindMenu(this.requestMethod())
            .width(100)
          TextInput({placeholder:"http:"})
            .onChange((url)=>{
              this.url=url;
            })
        }
        Row(){
          Button("设置参数")
            .fontSize(25)
            .onClick(()=>{
               this.dialogController.open();
            })
        }
        .margin({top:5,bottom:10})
          
        Button("发送请求")
          .fontSize(25)
          .onClick(()=>{
              this.setParamIfNecessary();
              httpService.requestHttp(this.url,this.requestParam);
              this.resetRequestParam();
          })
      }
      .width('100%')
      .height('100%')
  }

  /**
   * 请求发送完之后,重置参数
   */
  resetRequestParam(){
     this.requestParam=null;
  }

  /**
   * 若没有给请求设置参数,则使用默认的参数
   */
  setParamIfNecessary(){
    if(this.requestParam==null){
      this.requestParam={
        method: this.selectedMethod,
        header: {
          'content-type': 'application/json'
        },
        readTimeout: 60000, // default is 60s
        connectTimeout: 60000 // default is 60s.
      }
    }
  }

  /**
   *传递给对话框的回调函数,将对话框输入的参数封装为对象
   */
  setParamCallback(keys:string[],values:string[]){
    let extraData=this.buildExtraData(keys,values);
    this.requestParam = {
      header: {
        "content-type": "application/json"
      },
      method: this.selectedMethod,
      extraData: extraData,
      readTimeout: 60000, // default is 60s
      connectTimeout: 60000 // default is 60s.
    }
  }

  /**
   * 封装请求参数为一个对象
   */
  buildExtraData(keys:string[],values:string[]){
    let extraData={};
    for(let i=0;i<keys.length;i++){
      extraData[keys[i]]=values[i];
    }
    return extraData;
  }
}

创建入口页面

在ets/pages目录下创建index.ets文件。在该文件中导入HttpRequest.ets组件创建程序的入口页面。

import {HttpRequest} from '../component/HttpRequest'

@Entry
@Component
struct Index {
  build() {
    Column(){
      HttpRequest()
    }
  }
}

页面最终效果预览:

测试结果

开发板型号:WAGNER

OH版本:3.2.5.5

发送GET请求

测试的url: https://reqres.in/api/users?page=2

日志打印:

//响应头信息:
08-03 16:52:33.702  6439  6439 I 02200/JsApp: HttpDemo: ResponseHeader:{"access-control-allow-origin":"*","age":"1998","cache-control":"max-age=14400","cf-cache-status":"HIT","cf-ray":"734dd15b999e7da
c-LAX","connection":"keep-alive","content-encoding":"gzip","content-type":"application/json; charset=utf-8","date":"Wed, 03 Aug 2022 08:52:33 GMT","etag":"W/\"406-ut0vzoCuidvyMf8arZpMpJ6ZRDw\"","expec
t-ct":"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"","expires":"Wed, 03 Aug 2022 09:52:32 GMT","location":"https://reqres.in/api/users?page=2","nel":"{\"su
ccess_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=65aGmR0ar0fCc%2BGz5YrBCPBBUwmzeA%2BDUDIEiePrK2
XvwICV9KBBBuj0vIxq4RP0G7%2F%2BKwhOuR8d8PnT1IEIqpStt2taYJ%2F%2B3fj4JjxjU2Sddgys%2FCMVtQSJW7qtbfT8MnZq3asH4A%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","transfer-encoding"
:"chunked","vary":"Accept-Encoding","via":"1.1 vegur","x-powered-by":


08-03 16:52:33.702  6439  6439 I 02200/JsApp: HttpDemo: send request sucess

//响应内容
08-03 16:52:33.702  6439  6439 I 02200/JsApp: HttpDemo: the result is:{code:200,data:{"page":2,"per_page":6,"total":12,"total_pages":2,"data":[{"id":7,"email":"michael.lawson@reqres.in","first_name":"
Michael","last_name":"Lawson","avatar":"https://reqres.in/img/faces/7-image.jpg"},{"id":8,"email":"lindsay.ferguson@reqres.in","first_name":"Lindsay","last_name":"Ferguson","avatar":"https://reqres.in
/img/faces/8-image.jpg"},{"id":9,"email":"tobias.funke@reqres.in","first_name":"Tobias","last_name":"Funke","avatar":"https://reqres.in/img/faces/9-image.jpg"},{"id":10,"email":"byron.fields@reqres.in
","first_name":"Byron","last_name":"Fields","avatar":"https://reqres.in/img/faces/10-image.jpg"},{"id":11,"email":"george.edwards@reqres.in","first_name":"George","last_name":"Edwards","avatar":"https
://reqres.in/img/faces/11-image.jpg"},{"id":12,"email":"rachel.howell@reqres.in","first_name":"Rachel","last_name":"Howell","avatar":"https://reqres.in/img/faces/12-image.jpg"}],"support":{"url":"http
s://reqres.in/#support-heading","text":"To keep ReqRes free, contribu

发送POST请求

测试的url: https://reqres.in/api/users 参数:

{
  "name":"morpheus",
  "job":"leader"
}

日志打印:

//响应头信息:
08-03 17:00:17.796  6439  6439 I 02200/JsApp: HttpDemo: ResponseHeader:{"access-control-allow-origin":"*","cache-control":"max-age=3600","cf-cache-status":"DYNAMIC","cf-ray":"734ddcb00acf5281-LAX","co
nnection":"keep-alive","content-length":"51","content-type":"application/json; charset=utf-8","date":"Wed, 03 Aug 2022 09:00:17 GMT","etag":"W/\"33-wOvBK8Nue+Ck3OlpSqu8QL5bQlI\"","expect-ct":"max-age=
604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"","expires":"Wed, 03 Aug 2022 10:00:16 GMT","location":"https://reqres.in/api/users","nel":"{\"success_fraction\":0,\"r
eport_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=096ZxRLklCMfXbATfkCIKKHVMpSiEnPqDsg%2FH6qZzSkV9SsgEZGbr%2BiPJEqvIjbK
q0vUdmSf66q2gl8Tb14tgNp6b1TEbf%2Fg1IJVOZNNYi5m5Wb%2FaXUjCc4wXFVdXnLg8Uojxk7DPg%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","transfer-encoding":"chunked","vary":"Accept-En
coding","via":"1.1 vegur","x-powered-by":"Express"}


08-03 17:00:17.796  6439  6439 I 02200/JsApp: HttpDemo: send request sucess

//响应内容
08-03 17:00:17.796  6439  6439 I 02200/JsApp: HttpDemo: the result is:{code:201,data:{"id":"846","createdAt":"2022-08-03T09:00:17.537Z"}}

发送PUT请求

测试的url: https://reqres.in/api/users/2

参数:

{
  "name":"morpheus",
  "job":"zion resident"
}

日志打印:

//响应头信息:
08-03 17:02:00.411  6439  6439 I 02200/JsApp: HttpDemo: ResponseHeader:{"access-control-allow-origin":"*","cache-control":"max-age=3600","cf-cache-status":"DYNAMIC","cf-ray":"734ddf30ed467add-LAX","co
nnection":"keep-alive","content-length":"40","content-type":"application/json; charset=utf-8","date":"Wed, 03 Aug 2022 09:02:00 GMT","etag":"W/\"28-3PvShaMs/ugdjKvpR1lS0+UyqjQ\"","expect-ct":"max-age=
604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"","expires":"Wed, 03 Aug 2022 10:01:58 GMT","location":"https://reqres.in/api/users/2","nel":"{\"success_fraction\":0,\
"report_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=409PQEWa3s3L1hO7EGdMvoi19ChvQfyhXJWmwspO79yOYiLOA665haY9mse4apGcNj
uLo8JHCEsRDPrNk0UUqiIYOn4d5t7AF4ewaet5QVxCsB%2Fx%2BG6fzQgRtU0A0ZdkNvqZU2QDrA%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","transfer-encoding":"chunked","vary":"Accept-Enco
ding","via":"1.1 vegur","x-powered-by":"Express"}
08-03 17:02:00.412  6439  6439 I 02200/JsApp: HttpDemo: send request sucess


//响应内容
08-03 17:02:00.412  6439  6439 I 02200/JsApp: HttpDemo: the result is:{code:200,data:{"updatedAt":"2022-08-03T09:02:00.068Z"}}

发送DELETE请求

测试的url: https://reqres.in/api/users/2

日志打印:

//响应头信息:
08-03 17:02:55.093  6439  6439 I 02200/JsApp: HttpDemo: ResponseHeader:{"access-control-allow-origin":"*","cache-control":"max-age=3600","cf-cache-status":"DYNAMIC","cf-ray":"734de0865f4e7e1c-LAX","co
nnection":"keep-alive","date":"Wed, 03 Aug 2022 09:02:54 GMT","etag":"W/\"2-vyGp6PvFo4RvsFtPoIWeCReyIC8\"","expect-ct":"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/ex
pect-ct\"","expires":"Wed, 03 Aug 2022 10:02:53 GMT","location":"https://reqres.in/api/users/2","nel":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\"
:[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=N66IndbYWWvUovc%2Bp4irrFXzr%2Bf3cV5xwgz9MPbv49eVZpF9tPWeKBFr4UbgMNmGQ1kRb8DoiqpcG81GD%2FrzhzH818MBCVT1BrZ1iYXyocny1lVyBBN5CuI5%2Bzc5vwCGHp
m0HqnvLw%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","transfer-encoding":"chunked","vary":"Accept-Encoding","via":"1.1 vegur","x-powered-by":"Express"}


08-03 17:02:55.093  6439  6439 I 02200/JsApp: HttpDemo: send request sucess

//响应内容
08-03 17:02:55.093  6439  6439 I 02200/JsApp: HttpDemo: the result is:{code:204,data:}

参考文献

[1] 应用权限列表. https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md

[2] 使用ArkTS语言开发(Stage模型). https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md

[3] Http数据请求. https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/connectivity/http-request.md

[4] Http接口介绍. https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-http.md

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部