• 请不要在回答技术问题时复制粘贴 AI 生成的内容
drymonfidelia
V2EX  ›  程序员

tauri 真的太难用了,浪费了我整整一天

  •  1
     
  •   drymonfidelia · Feb 3, 2024 · 17767 views
    This topic created in 1004 days ago, the information mentioned may be changed or developed.

    天天看 V2 有人吹 tarui ,刚好有客户反应我们客户端太大了,于是给公司打包新网站(启动动画播完 location.href 跳转到线上地址,没别的功能)成 exe 的时候想试一下

    我们网站检测是否客户端访问是检测请求头的 app-name 字段是否有值(有个中间件,全部请求都检测)

    Electron 非常简单,三行代码搞定

     session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
        details.requestHeaders['app-name'] ='myapp'
        details.requestHeaders['app-ver'] = '1.0-win'
        details.requestHeaders['app-iver'] = '20240202-01M'
        
        callback({ requestHeaders: details.requestHeaders })
      })
    

    tauri 这个问题 Google 能搜到 4 篇讨论贴,实际给出方案的只有这一篇 https://github.com/tauri-apps/tauri/discussions/4912

    有人在下面提问说编译不了,快半年了没人回复

    我看 Rust 和 tauri 文档折腾了一天还没搞定,放弃了,用 Electron 3 分钟打好包提交 (最后还被领导骂了这么简单一个需求弄了一天是不是又在上班时间打游戏)

    附上我改的最后一版,还是不行,有能力的 V 友看看要写多少行才能实现这个简单的功能

    fn main() {
        tauri::Builder::default()
            .setup(|app| {
                let main_window = app.get_window("main").unwrap();
                main_window.with_webview(|webview| unsafe {
                    let core = webview.controller().CoreWebView2().unwrap();
                    let mut token: EventRegistrationToken = EventRegistrationToken::default();
                    core.AddWebResourceRequestedFilter("*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL);
                    core.add_WebResourceRequested(
                        CoreWebView2WebResourceRequestedEventHandler::create(Box::new(move |sender, args| {
                            if let Some(args) = args {
                                let request: ICoreWebView2WebResourceRequest = args.Request().unwrap();
                                request
                                    .Headers()
                                    .unwrap()
                                    .SetHeader("app-name", "myapp")
                                    .SetHeader("app-ver", "1.0-win")
                                    .SetHeader("app-iver", "20240202-01W")
                                    .unwrap();
                            }
                            Ok(())
                        })),
                        &mut token,
                    );
                });
                Ok(())
            })
            .invoke_handler(tauri::generate_handler![greet])
            .run(tauri::generate_context!())
            .expect("error while running tauri application");
    }
    
    63 replies  •  2024-04-24 14:45:50 +08:00
    roycestevie6761
    roycestevie6761
    Feb 3, 2024❤️1
    1
    rust 只适合当前问题没有解决方案,可能学一下 rust 搞一搞,如果有其他成熟的的替代方案,强行 rust 没啥意义,其他语言和框架至少迭代十年了都
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    2
    @roycestevie6761 正常 v 友推荐的灵车我是不敢碰的,但是 tauri GitHub 上有 73.5k star 感觉很成熟了,试了下,没想到连改个默认请求头都做不到
    roycestevie6761
    roycestevie6761
    Feb 3, 2024
    3
    @drymonfidelia 这个框架我没用过,但是 73K 不至于吧
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    4
    @roycestevie6761 但凡他的 star 数少一点,我早就放弃折腾了
    dcsuibian
    dcsuibian
    Feb 3, 2024❤️1
    5
    看来你之前上班时间打游戏被发现了呀
    oldManNewThought
    oldManNewThought
    Feb 3, 2024 via Android❤️2
    6
    https://tauri.app/v1/api/js/http
    设个 header 而已。肯定支持。记得 allowlist 添加域名。深入一点用下你会发现 tauri 真的比 electron 好。开箱即用的前端框架,简单明了的 api 。
    CLMan
    CLMan
    Feb 3, 2024❤️23
    7
    用一个你没学过的(复杂)语言,干一件你不熟悉的事情(使用 tauri 框架),然后怪这东西太难用了。
    iorilu
    iorilu
    Feb 3, 2024
    8
    赶时间的时候不要用不熟悉的新技术

    仅凭这点并不难说明 tauri 不好, 毕竟学任何新东西都要花时间的
    jeesk
    jeesk
    Feb 3, 2024 via Android
    9
    呵呵。 如果是一个听别人说就敢用上生产的团队, 显示不合格的, 还是要自己探索。
    guguji5
    guguji5
    Feb 3, 2024
    10
    electron 也是垃圾,在 mac 上鼓捣了半天都没打成功 exe (也可能是我菜
    hancai
    hancai
    Feb 3, 2024
    11
    我这两台也在折腾这玩意儿,rust 还是用不惯
    ie88
    ie88
    Feb 3, 2024
    12
    ```ts
    import { fetch } from '@tauri-apps/api/http';
    const response = await fetch('http://localhost:3003/users/2', {
    method: 'GET',
    timeout: 30,
    });
    ```

    试着 把 fetch 封装一下,类似于 axios 的做法

    ```ts
    async function my_fetch(url: Url, config: Config) {
    let custom_headers = {
    "app-name": "myapp",
    "app-ver": "1.0",
    ...
    };
    await fetch(url, {
    ...custom_headers,
    ...config
    });
    }
    ```

    然后 每次调用 my_fetch
    request 同理
    不用管我上面的具体代码,没有 IDE 不会写了...
    NessajCN
    NessajCN
    Feb 3, 2024❤️4
    13
    自己菜不要怪框架,谁让你用 webview 去折腾 headers 了?

    struct ReqClient {
    client: reqwest::Client

    }
    impl ReqClient {
    fn new(client: reqwest::Client) -> Self {
    Self {client}
    }

    tauri::Builder::default().
    .setup( |app| {
    let mut headers = reqwest::header::HeaderMap::new();
    headers.insert("app-name", header::HeaderValue::from_static("my-app"));
    headers.insert("app-ver", header::HeaderValue::from_static("1.0-win"));
    headers.insert("app-iver", header::HeaderValue::from_static("20240202-01M"));

    let client = reqwest::Client::builder().default_headers(headers).build().unwrap();
    app.manage(ReqClient::new(client));
    }
    //......
    mscorlib
    mscorlib
    Feb 3, 2024
    14
    用过 electron 、wails 、tauri
    目前公司在用 wails 做产品,部分产品正在用 electron 开发和改造
    这仨只能说各有优劣
    如果是开发 UI ,底层交互和计算比较少且不介意个头,推荐用 electron ,后面两个跟这个不是一个级别的东西,webview 安全机制会让你很多事做不了,还有 webview 在跨平台的时候 ui 会有差异。
    推荐用自己熟悉的且好招人的语言,rust 招人几乎不可能。。
    silomrelephant
    silomrelephant
    Feb 3, 2024❤️1
    15
    吐槽一下,unwrap 没事不要乱用,可以用 map ,flatmap 直接操作容器里面的内容,另外异常的路径最好也要养成习惯处理,即使打印日志也是好的
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    16
    @NessajCN 编译不了啊 failed to resolve: use of undeclared crate or module `reqwest` 全替换成 request 也不行
    ```
    fn main() {
    struct ReqClient {
    client: request::Client

    }
    impl ReqClient {
    fn new(client: request::Client) -> Self {
    Self {client}
    }
    }
    tauri::Builder::default()
    .setup( |app| {
    let mut headers = request::header::HeaderMap::new();
    headers.insert("app-name", header::HeaderValue::from_static("my-app"));
    headers.insert("app-ver", header::HeaderValue::from_static("1.0-win"));
    headers.insert("app-iver", header::HeaderValue::from_static("20240202-01M"));

    let client = request::Client::builder().default_headers(headers).build().unwrap();
    app.manage(ReqClient::new(client));
    })
    }
    ```
    ```
    error[E0433]: failed to resolve: use of undeclared crate or module `request`
    --> src\main.rs:20:22
    |
    20 | let client = request::Client::builder().default_headers(headers).build().unwrap();
    | ^^^^^^^ use of undeclared crate or module `request`

    error[E0433]: failed to resolve: use of undeclared crate or module `request`
    --> src\main.rs:15:27
    |
    15 | let mut headers = request::header::HeaderMap::new();
    | ^^^^^^^ use of undeclared crate or module `request`
    |
    help: consider importing this struct
    |
    1 + use tauri::http::header::HeaderMap;
    |
    help: if you import `HeaderMap`, refer to it directly
    |
    15 - let mut headers = request::header::HeaderMap::new();
    15 + let mut headers = HeaderMap::new();
    |

    error[E0433]: failed to resolve: use of undeclared crate or module `header`
    --> src\main.rs:16:36
    |
    16 | headers.insert("app-name", header::HeaderValue::from_static("my-app"));
    | ^^^^^^ use of undeclared crate or module `header`
    |
    help: consider importing this struct
    |
    1 + use tauri::http::header::HeaderValue;
    |
    help: if you import `HeaderValue`, refer to it directly
    |
    16 - headers.insert("app-name", header::HeaderValue::from_static("my-app"));
    16 + headers.insert("app-name", HeaderValue::from_static("my-app"));
    |

    error[E0433]: failed to resolve: use of undeclared crate or module `header`
    --> src\main.rs:17:35
    |
    17 | headers.insert("app-ver", header::HeaderValue::from_static("1.0-win"));
    | ^^^^^^ use of undeclared crate or module `header`
    |
    help: consider importing this struct
    |
    1 + use tauri::http::header::HeaderValue;
    |
    help: if you import `HeaderValue`, refer to it directly
    |
    17 - headers.insert("app-ver", header::HeaderValue::from_static("1.0-win"));
    17 + headers.insert("app-ver", HeaderValue::from_static("1.0-win"));
    |

    error[E0433]: failed to resolve: use of undeclared crate or module `header`
    --> src\main.rs:18:36
    |
    18 | headers.insert("app-iver", header::HeaderValue::from_static("20240202-01M"));
    | ^^^^^^ use of undeclared crate or module `header`
    |
    ```
    错误太多了贴不完
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    17
    @ie88 tauri 只是拿来当套壳浏览器,不能改动现有网页代码
    NessajCN
    NessajCN
    Feb 3, 2024
    18
    @drymonfidelia
    大哥,你这对 rust 是一点不懂就来用 tauri 了啊?
    cargo add reqwest
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    19
    @NessajCN 编译好了,请求头还是没设置上

    ```
    use reqwest::header::HeaderValue;
    use tauri::Manager; // Import the Manager trait
    fn main() {
    struct ReqClient {
    client: reqwest::Client,
    }
    impl ReqClient {
    fn new(client: reqwest::Client) -> Self {
    Self { client }
    }
    }

    tauri::Builder::default().setup(|app| {
    let mut headers = reqwest::header::HeaderMap::new();
    headers.insert("app-name", reqwest::header::HeaderValue::from_static("my-app"));
    headers.insert("app-ver", reqwest::header::HeaderValue::from_static("1.0-win"));
    headers.insert("app-iver", reqwest::header::HeaderValue::from_static("20240202-01M"));

    let client = reqwest::Client::builder()
    .default_headers(headers)
    .build()
    .unwrap();
    app.manage(ReqClient::new(client));
    Ok(())
    })
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
    }
    ```
    iorilu
    iorilu
    Feb 3, 2024
    20
    一定要牢记, 不要在公司生成环境, 有时间要求时候自作聪明搞不熟得新技术, 省的给领导留下不好印象
    NessajCN
    NessajCN
    Feb 3, 2024
    21
    @drymonfidelia
    你是不是对 tauri 的用法有很大的误解?它不是给你用来当套壳浏览器的,所谓的 js 前端只是个画 ui 的工具,你甚至不能在前端用 fetch 或 axios 这些前端请求工具。
    我发你的这段代码是让你生成好 state 后在 rust 后端发请求然后返回给前端显示的。你得在 command 函数里调用 req_client.client.get()
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    22
    @NessajCN 但是我的目的就是拿来当套壳浏览器,之前我的 /t/989348 /t/1011628 两个帖子都很多人无脑推荐 tauri 。
    同需求 Electron 就能非常方便实现
    zeusho871
    zeusho871
    Feb 3, 2024 via Android
    23
    用 wails ,我在 mac windows 成功了
    NessajCN
    NessajCN
    Feb 3, 2024
    25
    @drymonfidelia 我看了一下,是你自己没表达清楚
    你标题问的是 「我要做一个专用浏览器」
    但你实际的需求是「选一个现成浏览器好方便地显示我们的网页」

    你能分清「自己手搓浏览器」和「给自己网页套个现成浏览器的壳」这两者之间的区别吧?
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    26
    @NessajCN 「我要做一个专用浏览器」应该是比「选一个现成浏览器好方便地显示我们的网页」更底层的需求,我认为是应该更能实现改个默认请求头这种简单需求
    NessajCN
    NessajCN
    Feb 3, 2024 via Android❤️1
    27
    @drymonfidelia 确实更能实现啊,我不就用 3 分钟写了实现代码吗
    只不过 tauri 它真不是你要的现成浏览器啊。
    你要类比,前端 js 在这里的作用完全是 qml 在 qt 里的作用,也就是画个静态页面当 ui
    你想拿 tauri 来访问其他网站并且完美的显示在前端 ui ,那你当然得在 rust 里写 get 函数,并且自己重新手动写前端静态显示代码。说到底 tauri 它是个「 Rust gui 」框架而不是浏览器。
    ShadowPower
    ShadowPower
    Feb 3, 2024
    28
    其实两者的用途不太一样……

    Electron 适合直接把网页打包成应用,或者以 JavaScript/TypeScript 为主的应用。
    而 Tauri 的定位则是为 Rust 程序提供一个界面,只是界面部分使用系统的 WebView 来实现。
    djs
    djs
    Feb 3, 2024
    29
    专用浏览器用这个?不是应该直接干一个 chromium 下来自己编译吗
    ShadowPower
    ShadowPower
    Feb 3, 2024
    30
    对了,顺便一提,Tauri 的规划里其实还有抛弃 WebView ,自己实现界面绘制,虽然我感觉大概率走不通这条路。
    但是可以从这一点看出来,Tauri 的目标和 Electron 其实完全不一样,只是恰巧有一些交集……
    changdy
    changdy
    Feb 3, 2024
    31
    @guguji5 我没记错的话 ..好像几种桌面 gui 都是仅支持各自生态下打包各自的安装包.
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    32
    @dcsuibian 我们公司是交代的事情干完了,上班时间看 AV 都没人管你
    nebkad
    nebkad
    Feb 3, 2024❤️1
    33
    这帖子真的太难顶了,浪费了我整整一分钟
    araraloren
    araraloren
    Feb 3, 2024
    34
    @nebkad 就是在钓鱼。。
    0x723b
    0x723b
    Feb 3, 2024
    35
    如果你的需求是拦截 webview 的请求并添加 header 的话,根据 https://github.com/tauri-apps/tauri/discussions/4690 , 似乎是无法实现的
    drymonfidelia
    drymonfidelia
    OP
    Feb 3, 2024
    36
    @araraloren 看什么都钓鱼 我要钓鱼写这么长代码干什么 能钓鱼的话题多了去了
    lisongeee
    lisongeee
    Feb 3, 2024
    37
    所以 tauri 到底能不能实现拦截并修改 webview 的任意请求?

    有时候需要在 webview 里放置同公司其它组的业务页面,然后拦截加上自定义登录参数

    这种需求虽然不敢说不多见但是也不敢说不少见
    rming
    rming
    Feb 3, 2024❤️1
    38
    tauri 确实不够完善,关于 webview2 设置问题可以参考下这个 https://github.com/tauri-apps/tauri/issues/4284 和这个 https://docs.rs/webview2-com/latest/webview2_com/Microsoft/Web/WebView2/Win32/struct.ICoreWebView2HttpRequestHeaders.html#method.SetHeader 手机随便搜了下,仅供参考
    kkk9
    kkk9
    Feb 4, 2024❤️1
    39
    @lisongeee #37 rust 里写一个类 fetch 函数,js 内替换原来的 fetch ,实际调用的是这个函数。

    tauri 调用 webview 的 api 来干活,一切规则需要遵循系统 webview ,并不能自定义或者修改核心

    electron 本质上是一个 chromium 浏览器的,提供各种封装好的 API ,支持自定义,可以修改核心
    CLMan
    CLMan
    Feb 4, 2024❤️1
    40
    你的思路没什么问题,但知识储备跟不上,这个问题涉及到 win32 api ,而且 rust 语言本身是一个很难学的语言。

    下面是解决方案:
    -----
    // Prevents additional console window on Windows in release, DO NOT REMOVE!!
    #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

    use tauri::Manager;
    use webview2_com::{Microsoft::Web::WebView2::Win32::{ICoreWebView2WebResourceRequest, COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL}, WebResourceRequestedEventHandler};
    use windows::{core::HSTRING, Win32::System::WinRT::EventRegistrationToken};

    fn main() {
    tauri::Builder::default()
    .setup(|app| {
    let main_window = app.get_window("main").unwrap();
    main_window.with_webview(|webview| unsafe {
    let core = webview.controller().CoreWebView2().unwrap();
    let mut _token: EventRegistrationToken = EventRegistrationToken::default();
    core.AddWebResourceRequestedFilter(&HSTRING::from("*"), COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL).unwrap();
    core.add_WebResourceRequested(
    &WebResourceRequestedEventHandler::create(Box::new(move |_webview, args| {
    if let Some(args) = args {
    let request: ICoreWebView2WebResourceRequest = args.Request().unwrap();
    request
    .Headers()
    .unwrap()
    .SetHeader(&HSTRING::from("key1"), &HSTRING::from("value1"))
    .unwrap();
    }
    Ok(())
    })), &mut _token).unwrap();
    }).unwrap();
    Ok(())
    })
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
    }
    CLMan
    CLMan
    Feb 4, 2024
    41
    @CLMan 需要添加依赖(为了避免兼容性问题,与你使用的 tauri 版本保持一致,可以使用 IDE 的依赖管理功能查看)

    [dependencies]
    webview2-com = "0.19.1"
    windows = "0.39.0"
    Eiden
    Eiden
    Feb 4, 2024❤️1
    42
    op 是懂提问题的艺术的
    guguji5
    guguji5
    Feb 4, 2024
    43
    // 我没记错的话 ..好像几种桌面 gui 都是仅支持各自生态下打包各自的安装包.

    @changdy 好像也能打,但是一路报错,不知道是哪里不兼容。给我气坏了
    winmagic
    winmagic
    Feb 4, 2024 via Android
    44
    img src 访问 http 协议,不支持这个问题有遇到过吗,csp 设置了好像不行
    pdxjun
    pdxjun
    Feb 4, 2024
    45
    放弃 rust 吧,这是个缝合怪,个人感觉,缝合的还不是很好
    NessajCN
    NessajCN
    Feb 4, 2024
    46
    对了,今天 tauri 2.0 beta 出来了,你已经可以在前端用现成打包好的 reqwest 了
    https://beta.tauri.app/features/http-client/

    tauri::Builder::default()
    // Initialize the plugin
    .plugin(tauri_plugin_http::init())
    .run(tauri::generate_context!())
    .expect("error while running tauri application");


    import { fetch } from '@tauri-apps/plugin-http';

    // Send a GET request
    const response = await fetch('http://my.api.host/data.json', {
    method: 'GET',
    });
    console.log(response.status); // e.g. 200
    console.log(response.statusText); // e.g. "OK"
    githmb
    githmb
    Feb 4, 2024
    47
    总结:不想改前端代码
    drymonfidelia
    drymonfidelia
    OP
    Feb 4, 2024
    48
    @githmb 前端代码是其它部门写好的 哪有办法说改就改
    drymonfidelia
    drymonfidelia
    OP
    Feb 4, 2024
    49
    @kkk9 他需要在 webview 里放置同公司其它组的业务页面,很有可能这些页面是服务器渲染的,你替换掉原来的 fetch ,加载页面又不会调用 fetch ,没用
    @lisongeee
    kkk9
    kkk9
    Feb 4, 2024
    50
    @drymonfidelia #49 所以才需要技术选型。这个问题本身就不是 tauri 和 electron 的问题,是用的人有问题。😂
    adoal
    adoal
    Feb 4, 2024
    51
    tauri
    是:用 web 前端技术栈开发本机 UI 的框架;不是:嵌入浏览器访问现成网站。
    是:支持多个平台运行的本机 UI 框架;不是:避开不同浏览器行为差异的“跨平台”框架。
    CLMan
    CLMan
    Feb 4, 2024❤️1
    52
    @drymonfidelia 我前面给出的方案修复了你代码里面的语法错误,你都不看一眼吗?
    CLMan
    CLMan
    Feb 4, 2024❤️1
    53
    @drymonfidelia 在我本机上实测,可以正确设置 header 。
    drymonfidelia
    drymonfidelia
    OP
    Feb 4, 2024
    54
    @CLMan 谢谢 今天放假了,在路上没有电脑测试
    djkloop
    djkloop
    Feb 4, 2024
    55
    @drymonfidelia #32 细说
    wangtian2020
    wangtian2020
    Feb 5, 2024
    56
    看到 electron 又赢了,我就放心了
    secondwtq
    secondwtq
    Feb 5, 2024
    57
    算是把 Cunningham's Law 玩儿明白了 ...
    wocao666
    wocao666
    Feb 5, 2024
    58
    @drymonfidelia 这么爽??我上班学个习,领导看见了都时不时交代点工作给我干了
    iugo
    iugo
    Feb 5, 2024
    59
    可能需求不一样吧, 我们的 Web 没有做服务端渲染, 所以类似需求的实现方式是前端 JS 检查了一些信息后 API 请求到服务器. 而不是在跳转页面的时候修改请求头.
    drymonfidelia
    drymonfidelia
    OP
    Feb 5, 2024
    60
    @CLMan #40 的代码可以用,谢谢
    ungrownxiaohao
    ungrownxiaohao
    Feb 19, 2024
    61
    @roycestevie6761 #3 你好,rust 社区是这样的,争着抢着要“改天换地”
    uLdP4HCJts79jh56
    uLdP4HCJts79jh56
    Mar 29, 2024 via Android
    62
    @lisongeee 拦截不能,获取 webview 里的 cookie 也不行,有维护者在 issue 里回复过对 webview 控制力很弱
    seu
    seu
    Apr 24, 2024
    63
    不行 issue 里面有明确的说过 可能会考虑在 v3 版本添加 现在的技术路线图不包含这块
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   3481 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 111ms · UTC 04:19 · PVG 12:19 · LAX 20:19 · JFK 23:19
    ♥ Do have faith in what you're doing.