开天辟地 HarmonyOS(鸿蒙) - 网络: http(通过 rcp 实现 http 请求,基础)

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

开天辟地 HarmonyOS(鸿蒙) - 网络: http(通过 rcp 实现 http 请求,基础)

示例如下:

pages\network\RcpDemo.ets

/*
 * http 请求
 * 本例用于演示如何通过 rcp 实现 http 请求,基础
 * 相对于 Network Kit 的 HttpRequest 来说,通过 Remote Communication Kit 的 rcp 实现 http 请求会更简单且功能更强大
 *
 * 需要在 src/main/module.json5 中添加网络权限,类似如下
 * {
 *   "module": {
 *     "requestPermissions":[
 *       {
 *         "name" : "ohos.permission.INTERNET", // 使用 Internet 网络的权限
 *         "reason": "$string:hello_webabcd", // 申请此权限的原因
 *         "usedScene": {
 *           "abilities": [ ],
 *           "when":"always" // inuse(使用时允许使用此权限),always(始终允许使用此权限)
 *         }
 *       },
 *     ]
 *   }
 * }
 */

import {  TitleBar } from '../TitleBar';
import { rcp } from '@kit.RemoteCommunicationKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct RcpDemo {

  build() {
    Column() {
      TitleBar()
      Tabs() {
        TabContent() { MySample1() }.tabBar('get/post/fetch').align(Alignment.Top)
        TabContent() { MySample2() }.tabBar('自定义 headers, cookies 等').align(Alignment.Top)
        TabContent() { MySample3() }.tabBar('超时时间').align(Alignment.Top)
        TabContent() { MySample4() }.tabBar('取消请求').align(Alignment.Top)
      }
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .layoutWeight(1)
    }
  }
}

@Component
struct MySample1 {

  @State message: string = ""

  /*
   * rcp.createSession() - 创建一个 rcp.Session 对象
   * rcp.Session - 用于实现 http 请求的对象
   *   get(), post(), put(), head(), delete() - 发起指定的 http 请求
   *   fetch() - 通过 fetch 发起 http 请求
   *   close() - 关闭请求对象(注:如果 session 不再使用了,则需要调用此方法释放资源)
   * 注:一个 session 可以同时发起多个 http 请求,当某个 session 的所有请求都完成了再调用 close() 释放资源
   *
   * rcp.Response - http 请求的响应对象
   *   request - http 请求的请求对象
   *   statusCode - 响应的状态码
   *   headers - 响应的 header
   *   cookies - 响应的 cookie
   *   body - 响应的数据(一个 ArrayBuffer 对象)
   *   toString() - 将响应的数据转为字符串
   *   toJSON() - 将响应的数据转为 json 对象
   *
   * rcp.Request - http 请求的请求对象
   *   id - 请求的唯一标识,由系统生成
   *   url - 请求的 url
   *   method - 请求的方法
   *   headers - 请求的 header
   *   cookies - 请求的 cookie
   *   content - 请求的内容,比如 post 的数据
   *     可以是 string 或 ArrayBuffer 或 Form 或 object 等
   */

  async get_sample() {
    this.message = "开始 get 请求\n"

    const session: rcp.Session = rcp.createSession()
    session.get("http://192.168.8.197:8001/api?k1=v1&k2=v2").then((response: rcp.Response) => {
      this.message += `response code: ${response.statusCode}\n`
      this.message += `response string: ${response.toString()}\n`
      this.message += `response length: ${response.body?.byteLength}\n`
    }).catch((err: BusinessError) => {
      this.message += `error: ${JSON.stringify(err)}\n`
    }).finally(() => {
      session.close()
    });
  }

  async post_sample() {
    this.message = "开始 post 请求\n"
    const postData: rcp.RequestContent = {
        name: "webabcd",
        age: 44,
    }

    const session = rcp.createSession()
    session.post("http://192.168.8.197:8001/api?k1=v1&k2=v2", postData).then((response) => {
      this.message += `response result: ${response.toString()}\n`
    }).catch((err: BusinessError) => {
      this.message += `error: ${JSON.stringify(err)}\n`
    }).finally(() => {
      session.close()
    });
  }

  async fetch_sample() {
    this.message = "通过 fetch 做 http 请求\n"
    const request = new rcp.Request("http://192.168.8.197:8001/api?k1=v1&k2=v2", 'POST');
    request.content = "post data"

    const session = rcp.createSession()
    session.fetch(request).then((response) => {
      this.message += `response result: ${response.toString()}\n`
    }).catch((err: BusinessError) => {
      this.message += `error: ${JSON.stringify(err)}\n`
    }).finally(() => {
      session.close()
    });
  }

  build() {
    Column({space:10}) {
      Button("get").onClick(async () => {
        await this.get_sample()
      })

      Button("post").onClick(async () => {
        await this.post_sample()
      })

      Button("fetch").onClick(async () => {
        await this.fetch_sample()
      })

      Text(this.message)
    }
  }
}

@Component
struct MySample2 {

  @State message: string = ""

  /*
   * rcp.Request - http 请求的请求对象
   *   id - 请求的唯一标识,由系统生成
   *   url - 请求的 url
   *   method - 请求的方法
   *   headers - 请求的 header
   *   cookies - 请求的 cookie
   *   content - 请求的内容,比如 post 的数据
   *     可以是 string 或 ArrayBuffer 或 Form 或 object 等
   *
   * rcp.createSession() - 创建一个 rcp.Session 对象
   *   headers - 请求的 header(此处的 header 会合并到 rcp.Request 的 header 中,同名的则以 rcp.Request 中的为准)
   *   cookies - 请求的 cookie(此处的 cookie 会合并到 rcp.Request 的 cookie 中,同名的则以 rcp.Request 中的为准)
   */
  async fetch_sample() {
    this.message = "通过 fetch 做 http 请求\n"
    const request = new rcp.Request("http://192.168.8.197:8001/api?k1=v1&k2=v2");
    request.method = 'POST'
    request.headers = {
      'custom-header1': 'abc'
    }
    request.cookies = { }
    request.content = "post data"

    let session = rcp.createSession()
    session.fetch(request).then((response) => {
      this.message += `response result: ${response.toString()}\n`
    }).catch((err: BusinessError) => {
      this.message += `error: ${JSON.stringify(err)}\n`
    }).finally(() => {
      session.close()
    });
  }

  build() {
    Column({space:10}) {

      Button("自定义 headers, cookies 等").onClick(async () => {
        await this.fetch_sample()
      })

      Text(this.message)
    }
  }
}

@Component
struct MySample3 {

  @State message: string = ""

  /*
   * rcp.Request - http 请求的请求对象
   *   configuration.transfer.timeout - 请求的超时时间
   *     connectMs - 连接的最大时间,单位:毫秒
   *     transferMs - 数据传输的最大时间,单位:毫秒
   *     inactivityMs - 无数据传输的最大时间,单位:毫秒
   */
  async fetch_sample() {
    this.message = "通过 fetch 做 http 请求\n"
    const request = new rcp.Request("http://192.168.8.197:8001/api?k1=v1&k2=v2");
    request.configuration = {
      transfer: {
        timeout: {
          connectMs: 1000,
          transferMs: 2000,
          inactivityMs: 3000
        }
      }
    }

    let session = rcp.createSession()
    session.fetch(request).then((response) => {
      this.message += `response result: ${response.toString()}\n`
    }).catch((err: BusinessError) => {
      this.message += `error: ${JSON.stringify(err)}\n`
    }).finally(() => {
      session.close()
    });
  }

  build() {
    Column({space:10}) {

      Button("超时时间").onClick(async () => {
        await this.fetch_sample()
      })

      Text(this.message)
    }
  }
}

@Component
struct MySample4 {

  @State message: string = ""
  session?: rcp.Session

  async fetch_sample() {
    this.message = "通过 fetch 做 http 请求\n"
    const request: rcp.Request = new rcp.Request("http://192.168.8.197:8001/api?k1=v1&k2=v2", 'GET');
    this.session = rcp.createSession()
    this.session.fetch(request).then((response) => {
      this.message += `response result: ${response.toString()}\n`
    }).catch((err: BusinessError) => {
      this.message += `error: ${JSON.stringify(err)}\n`
    }).finally(() => {
      this.session?.close()
    });
  }

  /*
   * rcp.Session - 用于实现 http 请求的对象
   *   cancel() - 取消当前 session 的全部请求
   *   cancel(rcp.Request) - 取消当前 session 的指定的 rcp.Request 请求
   */
  async cancel() {
    this.session?.cancel()
    // this.session?.cancel(rcp.Request)
    this.session = undefined
  }

  build() {
    Column({space:10}) {

      Button("fetch").onClick(async () => {
        await this.fetch_sample()
      })

      Button("cancel").onClick(async () => {
        await this.cancel()
      })

      Text(this.message)
    }
  }
}

\webapi\webapi\webserver.py

from aiohttp import web
import asyncio

def setup_routes(app):
    app.router.add_route('*', '/api', httpapi)
    app.router.add_route('*', '/redirect', httpapi_redirect)
    app.router.add_route('*', '/upload', httpapi_upload)

async def launch():
    app = web.Application()
    runner = web.AppRunner(app)
    setup_routes(app)
    await runner.setup()
    site = web.TCPSite(runner, '0.0.0.0', 8001)
    await site.start()


async def httpapi(request):
    k1 = request.query.get('k1', '')
    k2 = request.query.get('k2', '')
    
    h1 = request.headers.get('custom-header1', '')
        
    data = await request.content.read()
    postData = data.decode()
        
    result = f"method:{request.method}, k1:{k1}, k2:{k2}, h1:{h1}, postData:{postData}"

    await asyncio.sleep(3)
    return web.Response(text=result)


async def httpapi_redirect(request):
    return web.Response(status=302, headers={'Location': '/api?k1=v1&k2=v2'})


async def httpapi_upload(request):
    filepath =  request.headers.get('filename', 'unknown.unknown')

    with open(filepath, 'wb') as f:
        while True:
            chunk = await request.content.read(1024 * 1024) 
            if not chunk:
                break
            f.write(chunk)

    return web.json_response({'message': f'文件成功保存到 {filepath}'}, status=200)

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

posted @ 2025-05-27 14:42  webabcd  阅读(75)  评论(0)    收藏  举报