V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
drymonfidelia
V2EX  ›  程序员

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

  •  1
     
  •   drymonfidelia · 116 天前 · 8682 次点击
    这是一个创建于 116 天前的主题,其中的信息可能已经有所发展或是发生改变。

    天天看 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 条回复    2024-04-24 14:45:50 +08:00
    roycestevie6761
        1
    roycestevie6761  
       116 天前   ❤️ 1
    rust 只适合当前问题没有解决方案,可能学一下 rust 搞一搞,如果有其他成熟的的替代方案,强行 rust 没啥意义,其他语言和框架至少迭代十年了都
    drymonfidelia
        2
    drymonfidelia  
    OP
       116 天前
    @roycestevie6761 正常 v 友推荐的灵车我是不敢碰的,但是 tauri GitHub 上有 73.5k star 感觉很成熟了,试了下,没想到连改个默认请求头都做不到
    roycestevie6761
        3
    roycestevie6761  
       116 天前
    @drymonfidelia 这个框架我没用过,但是 73K 不至于吧
    drymonfidelia
        4
    drymonfidelia  
    OP
       116 天前
    @roycestevie6761 但凡他的 star 数少一点,我早就放弃折腾了
    dcsuibian
        5
    dcsuibian  
       116 天前   ❤️ 1
    看来你之前上班时间打游戏被发现了呀
    oldManNewThought
        6
    oldManNewThought  
       116 天前 via Android   ❤️ 2
    https://tauri.app/v1/api/js/http
    设个 header 而已。肯定支持。记得 allowlist 添加域名。深入一点用下你会发现 tauri 真的比 electron 好。开箱即用的前端框架,简单明了的 api 。
    CLMan
        7
    CLMan  
       116 天前   ❤️ 23
    用一个你没学过的(复杂)语言,干一件你不熟悉的事情(使用 tauri 框架),然后怪这东西太难用了。
    iorilu
        8
    iorilu  
       116 天前
    赶时间的时候不要用不熟悉的新技术

    仅凭这点并不难说明 tauri 不好, 毕竟学任何新东西都要花时间的
    jeesk
        9
    jeesk  
       116 天前 via Android
    呵呵。 如果是一个听别人说就敢用上生产的团队, 显示不合格的, 还是要自己探索。
    guguji5
        10
    guguji5  
       116 天前
    electron 也是垃圾,在 mac 上鼓捣了半天都没打成功 exe (也可能是我菜
    hancai
        11
    hancai  
       116 天前
    我这两台也在折腾这玩意儿,rust 还是用不惯
    ie88
        12
    ie88  
       116 天前
    ```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
        13
    NessajCN  
       116 天前   ❤️ 4
    自己菜不要怪框架,谁让你用 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
        14
    mscorlib  
       116 天前
    用过 electron 、wails 、tauri
    目前公司在用 wails 做产品,部分产品正在用 electron 开发和改造
    这仨只能说各有优劣
    如果是开发 UI ,底层交互和计算比较少且不介意个头,推荐用 electron ,后面两个跟这个不是一个级别的东西,webview 安全机制会让你很多事做不了,还有 webview 在跨平台的时候 ui 会有差异。
    推荐用自己熟悉的且好招人的语言,rust 招人几乎不可能。。
    silomrelephant
        15
    silomrelephant  
       116 天前   ❤️ 1
    吐槽一下,unwrap 没事不要乱用,可以用 map ,flatmap 直接操作容器里面的内容,另外异常的路径最好也要养成习惯处理,即使打印日志也是好的
    drymonfidelia
        16
    drymonfidelia  
    OP
       116 天前
    @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
        17
    drymonfidelia  
    OP
       116 天前
    @ie88 tauri 只是拿来当套壳浏览器,不能改动现有网页代码
    NessajCN
        18
    NessajCN  
       116 天前
    @drymonfidelia
    大哥,你这对 rust 是一点不懂就来用 tauri 了啊?
    cargo add reqwest
    drymonfidelia
        19
    drymonfidelia  
    OP
       116 天前
    @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
        20
    iorilu  
       116 天前
    一定要牢记, 不要在公司生成环境, 有时间要求时候自作聪明搞不熟得新技术, 省的给领导留下不好印象
    NessajCN
        21
    NessajCN  
       116 天前
    @drymonfidelia
    你是不是对 tauri 的用法有很大的误解?它不是给你用来当套壳浏览器的,所谓的 js 前端只是个画 ui 的工具,你甚至不能在前端用 fetch 或 axios 这些前端请求工具。
    我发你的这段代码是让你生成好 state 后在 rust 后端发请求然后返回给前端显示的。你得在 command 函数里调用 req_client.client.get()
    drymonfidelia
        22
    drymonfidelia  
    OP
       116 天前
    @NessajCN 但是我的目的就是拿来当套壳浏览器,之前我的 /t/989348 /t/1011628 两个帖子都很多人无脑推荐 tauri 。
    同需求 Electron 就能非常方便实现
    zeusho871
        23
    zeusho871  
       116 天前 via Android
    用 wails ,我在 mac windows 成功了
    drymonfidelia
        24
    drymonfidelia  
    OP
       116 天前
    NessajCN
        25
    NessajCN  
       116 天前
    @drymonfidelia 我看了一下,是你自己没表达清楚
    你标题问的是 「我要做一个专用浏览器」
    但你实际的需求是「选一个现成浏览器好方便地显示我们的网页」

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

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

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

    这种需求虽然不敢说不多见但是也不敢说不少见
    rming
        38
    rming  
       115 天前   ❤️ 1
    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
        39
    kkk9  
       115 天前   ❤️ 1
    @lisongeee #37 rust 里写一个类 fetch 函数,js 内替换原来的 fetch ,实际调用的是这个函数。

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

    electron 本质上是一个 chromium 浏览器的,提供各种封装好的 API ,支持自定义,可以修改核心
    CLMan
        40
    CLMan  
       115 天前   ❤️ 1
    你的思路没什么问题,但知识储备跟不上,这个问题涉及到 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
        41
    CLMan  
       115 天前
    @CLMan 需要添加依赖(为了避免兼容性问题,与你使用的 tauri 版本保持一致,可以使用 IDE 的依赖管理功能查看)

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

    @changdy 好像也能打,但是一路报错,不知道是哪里不兼容。给我气坏了
    winmagic
        44
    winmagic  
       115 天前 via Android
    img src 访问 http 协议,不支持这个问题有遇到过吗,csp 设置了好像不行
    pdxjun
        45
    pdxjun  
       115 天前
    放弃 rust 吧,这是个缝合怪,个人感觉,缝合的还不是很好
    NessajCN
        46
    NessajCN  
       115 天前
    对了,今天 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
        47
    githmb  
       115 天前
    总结:不想改前端代码
    drymonfidelia
        48
    drymonfidelia  
    OP
       115 天前
    @githmb 前端代码是其它部门写好的 哪有办法说改就改
    drymonfidelia
        49
    drymonfidelia  
    OP
       115 天前
    @kkk9 他需要在 webview 里放置同公司其它组的业务页面,很有可能这些页面是服务器渲染的,你替换掉原来的 fetch ,加载页面又不会调用 fetch ,没用
    @lisongeee
    kkk9
        50
    kkk9  
       115 天前
    @drymonfidelia #49 所以才需要技术选型。这个问题本身就不是 tauri 和 electron 的问题,是用的人有问题。😂
    adoal
        51
    adoal  
       115 天前
    tauri
    是:用 web 前端技术栈开发本机 UI 的框架;不是:嵌入浏览器访问现成网站。
    是:支持多个平台运行的本机 UI 框架;不是:避开不同浏览器行为差异的“跨平台”框架。
    CLMan
        52
    CLMan  
       115 天前   ❤️ 1
    @drymonfidelia 我前面给出的方案修复了你代码里面的语法错误,你都不看一眼吗?
    CLMan
        53
    CLMan  
       115 天前   ❤️ 1
    @drymonfidelia 在我本机上实测,可以正确设置 header 。
    drymonfidelia
        54
    drymonfidelia  
    OP
       115 天前
    @CLMan 谢谢 今天放假了,在路上没有电脑测试
    djkloop
        55
    djkloop  
       115 天前
    @drymonfidelia #32 细说
    wangtian2020
        56
    wangtian2020  
       114 天前
    看到 electron 又赢了,我就放心了
    secondwtq
        57
    secondwtq  
       114 天前
    算是把 Cunningham's Law 玩儿明白了 ...
    wocao666
        58
    wocao666  
       114 天前
    @drymonfidelia 这么爽??我上班学个习,领导看见了都时不时交代点工作给我干了
    iugo
        59
    iugo  
       114 天前
    可能需求不一样吧, 我们的 Web 没有做服务端渲染, 所以类似需求的实现方式是前端 JS 检查了一些信息后 API 请求到服务器. 而不是在跳转页面的时候修改请求头.
    drymonfidelia
        60
    drymonfidelia  
    OP
       114 天前
    @CLMan #40 的代码可以用,谢谢
    ungrownxiaohao
        61
    ungrownxiaohao  
       100 天前
    @roycestevie6761 #3 你好,rust 社区是这样的,争着抢着要“改天换地”
    ejfkdev
        62
    ejfkdev  
       60 天前 via Android
    @lisongeee 拦截不能,获取 webview 里的 cookie 也不行,有维护者在 issue 里回复过对 webview 控制力很弱
    seu
        63
    seu  
       35 天前
    不行 issue 里面有明确的说过 可能会考虑在 v3 版本添加 现在的技术路线图不包含这块
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2931 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 12:39 · PVG 20:39 · LAX 05:39 · JFK 08:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.