【Tauri2】40——tauri-plugin-http

前言

这篇就来看看http这个插件,这个插件的用处也是显而易见的,发送请求。

简单使用一下

HTTP 客户端 | Taurihttps://v2.tauri.app/zh-cn/plugin/http-client/

正文

安装依赖

在Cargo.toml文件中

tauri-plugin-http ={version = "2"}

注册插件

.plugin(tauri_plugin_http::init())

后端使用

发送请求,这其实很简单

reqwest - Rusthttps://docs.rs/reqwest/latest/reqwest/使用reqwest这个crate。

说白了,这个插件就是对这个crate的封装。

因此,代码如下

use tauri_plugin_http::reqwest;
use std::fs;
use tauri::command;

#[command]
async fn fetch(){
    let client = reqwest::Client::new();
    let res = client.get("https://geo.datav.aliyun.com/areas_v3/bound/510100_full.json")
        .send()
        .await
        .unwrap();
    println!("{:?}", res);
    if res.status().is_success() {
        println!("请求成功");
        let text=res.text().await.unwrap();
        fs::write("output.json", text).unwrap();
    }
}

注册通信函数,并使用。

笔者如下网址发送请求,获取一些地理数据

https://geo.datav.aliyun.com/areas_v3/bound/100000_full.jsonhttps://geo.datav.aliyun.com/areas_v3/bound/100000_full.json具体含义就不必细说了

总之,成功了

在后端的使用就没了。

可以发送get、post等,基本操作,不必细说。

看看插件中注册的通信函数

  .invoke_handler(tauri::generate_handler![
            commands::fetch,
            commands::fetch_cancel,
            commands::fetch_send,
            commands::fetch_read_body
        ])

注册了四个,很显然,最重要的方法就是fetch,

前端也有fetch,

当前的 fetch 方法是一个 Rust 后端 API。 它试图与 fetch Web API 尽可能接近和兼容。

——tauri的官方文档

看来跟前端差不多

 在前端使用

安装依赖

pnpm tauri add http

这个命令,前后端都会安装。

代码如下

 async function clicked() {
        let response=await fetch("https://geo.datav.aliyun.com/areas_v3/bound/510100_full.json",{
            method:"GET",
        })
        let res=await response.json();
        console.log(res)
    }

这段代码要能成功,必然要配置权限,大部分前端的东西都需要配置权限

{
      "identifier": "http:default",
      "allow": [
        { "url": "http://*/*" },
        { "url": "https://*/*" }
      ]
}

配置运行所有的http和https

结果如下

 如果输出不出来,可能是版本依赖的问题,笔者在这里遇到了这个问题

https://github.com/tauri-apps/plugins-workspace/issues/2638https://github.com/tauri-apps/plugins-workspace/issues/2638

解决了。

如何发送请求

在开发者工具中,可以找到如下请求

首先使用fetch、然后使用fetch_send,然后使用fetch_read_body

最后使用plugin:__TAURI_CHANNEL__|Cfetch

从名字中,就可以看出fetch_send,这里发送了请求。

看看fetch_send

关键代码如下

#[command]
pub async fn fetch_send<R: Runtime>(
    webview: Webview<R>,
    rid: ResourceId,
) -> crate::Result<FetchResponse> {
    let (req, abort_rx) = {
           ...
    };
    let mut fut = req.fut.lock().await;
    let res = tokio::select! {
        res = fut.as_mut() => res?,
        _ = abort_rx.0 => {
            let mut resources_table = webview.resources_table();
            resources_table.close(rid)?;
            return Err(Error::RequestCanceled);
        }
    };


    ...

}

先获取到请求,使用tokio发送请求,里面实际上使用互斥锁,总之,各种封装。

看看fetch_read_body

关键代码如下

#[command]
pub async fn fetch_read_body<R: Runtime>(
    webview: Webview<R>,
    rid: ResourceId,
    stream_channel: Channel<tauri::ipc::InvokeResponseBody>,
) -> crate::Result<()> {
    let res = {
       ...
    };

    let mut res = Arc::into_inner(res).unwrap().0;

    // send response through IPC channel
    while let Some(chunk) = res.chunk().await? {
        let mut chunk = chunk.to_vec();
        // append 0 to indicate we are not done yet
        chunk.push(0);
        stream_channel.send(tauri::ipc::InvokeResponseBody::Raw(chunk))?;
    }
   ...
}

传入一个通道,把请求的结果传到通道里面。

原来这个是用来处理结果的,plugin:__TAURI_CHANNEL__|fetch

看看前端的处理

关键代码

在node_modules\.pnpm\@tauri-apps+plugin-http@2.4.3\node_modules\@tauri-apps\plugin-http\dist-js\index.js文件中,如下代码

    const readableStreamBody = new ReadableStream({
        start: (controller) => {
            const streamChannel = new Channel();
            streamChannel.onmessage = (res) => {
                
              ....
            }
            invoke('plugin:http|fetch_read_body', {
                rid: responseRid,
                streamChannel
            }).catch((e) => {
                controller.error(e);
            });
        }
    });
    const res = new Response(readableStreamBody, {
        status,
        statusText
    });

await response.json()时,就会触发start,

在里面初始化了一个管道Channel,定义了管道的onmessage

然后使用fetch_read_body,把Channel传进去

原来可以这样使用

这个Channel是core里面的

import { invoke, Channel } from '@tauri-apps/api/core';

使用channel

参考

Channel in tauri::ipc - RustAn IPC channel.https://docs.rs/tauri/latest/tauri/ipc/struct.Channel.html

不妨来使用这个channel

就以前面自定义的通信函数fetch中使用

代码如下

前端

import {invoke,Channel} from "@tauri-apps/api/core";    
    async function clicked() {
        const channel = new Channel();
        channel.onmessage=(res)=>{
            console.log(res);
        }
        await invoke("fetch",{"channel":channel})
    }

初始化通道,作为参数传递进去

后端

use tauri::ipc::Channel;
use tauri::ipc::InvokeResponseBody;
#[command]
async fn fetch(channel: Channel) {
    let client = reqwest::Client::new();
    let res = client
        .get("https://geo.datav.aliyun.com/areas_v3/bound/510100_full.json")
        .send()
        .await
        .unwrap();
    if res.status().is_success() {
        let result=res.text().await.unwrap();
        channel.send(InvokeResponseBody::Json(result)).unwrap();
    }
}

前端传入通道,使用send方法、返回json数据

结果如下

没问题

Channel

这个Channel是在通信函数中,实现了CommandArg 这个trait

实现了from_command这个方法

fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
    let name = command.name;
    let arg = command.key;
    let webview = command.message.webview();
    let value: String =
      Deserialize::deserialize(command).map_err(|e| crate::Error::InvalidArgs(name, arg, e))?;
    JavaScriptChannelId::from_str(&value)
      .map(|id| id.channel_on(webview))
      .map_err(|_| {
        InvokeError::from(format!(
	        "invalid channel value `{value}`, expected a string in the `{IPC_PAYLOAD_PREFIX}ID` format"
	      ))
      })
  }

从代码里面可以看出,需要获得value,因此需要将Channel作为参数传入。

然后,使用from_str这个方法获取Channel

因此,传一个字符串也可以,也不能乱传,需要有这个channel

比如使用前端的Channel对象的toJson方法,即

 await invoke("fetch",{"channel":channel.toJSON()});
// 或者使用
await invoke("fetch",{"channel":"__CHANNEL__:"+channel.id});

看请求

http://ipc.localhost/plugin:__TAURI_CHANNEL__|Cfetch

 可以发现__TAURI_CHANNEL__是一个插件,通信函数是fetch

简单看看是什么发出的请求参数

下面这段代码

window.__TAURI_INTERNALS__.invoke('plugin:__TAURI_CHANNEL__|fetch', null, {
    headers: {
        'Tauri-Channel-Id': '2'
    }
}).then( (response) => window['_2166646617']({
    message: response,
    index: 0
})).catch(console.error)

这个Channel挺有趣的,以后还会使用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值