天天看 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");
}
1
roycestevie6761 323 天前 1
rust 只适合当前问题没有解决方案,可能学一下 rust 搞一搞,如果有其他成熟的的替代方案,强行 rust 没啥意义,其他语言和框架至少迭代十年了都
|
2
drymonfidelia OP @roycestevie6761 正常 v 友推荐的灵车我是不敢碰的,但是 tauri GitHub 上有 73.5k star 感觉很成熟了,试了下,没想到连改个默认请求头都做不到
|
3
roycestevie6761 323 天前
@drymonfidelia 这个框架我没用过,但是 73K 不至于吧
|
4
drymonfidelia OP @roycestevie6761 但凡他的 star 数少一点,我早就放弃折腾了
|
5
dcsuibian 323 天前 1
看来你之前上班时间打游戏被发现了呀
|
6
oldManNewThought 323 天前 via Android 2
https://tauri.app/v1/api/js/http
设个 header 而已。肯定支持。记得 allowlist 添加域名。深入一点用下你会发现 tauri 真的比 electron 好。开箱即用的前端框架,简单明了的 api 。 |
7
CLMan 323 天前 23
用一个你没学过的(复杂)语言,干一件你不熟悉的事情(使用 tauri 框架),然后怪这东西太难用了。
|
8
iorilu 323 天前
赶时间的时候不要用不熟悉的新技术
仅凭这点并不难说明 tauri 不好, 毕竟学任何新东西都要花时间的 |
9
jeesk 323 天前 via Android
呵呵。 如果是一个听别人说就敢用上生产的团队, 显示不合格的, 还是要自己探索。
|
10
guguji5 323 天前
electron 也是垃圾,在 mac 上鼓捣了半天都没打成功 exe (也可能是我菜
|
11
hancai 323 天前
我这两台也在折腾这玩意儿,rust 还是用不惯
|
12
ie88 323 天前
```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 不会写了... |
13
NessajCN 323 天前 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)); } //...... |
14
mscorlib 323 天前
用过 electron 、wails 、tauri
目前公司在用 wails 做产品,部分产品正在用 electron 开发和改造 这仨只能说各有优劣 如果是开发 UI ,底层交互和计算比较少且不介意个头,推荐用 electron ,后面两个跟这个不是一个级别的东西,webview 安全机制会让你很多事做不了,还有 webview 在跨平台的时候 ui 会有差异。 推荐用自己熟悉的且好招人的语言,rust 招人几乎不可能。。 |
15
silomrelephant 323 天前 1
吐槽一下,unwrap 没事不要乱用,可以用 map ,flatmap 直接操作容器里面的内容,另外异常的路径最好也要养成习惯处理,即使打印日志也是好的
|
16
drymonfidelia OP @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` | ``` 错误太多了贴不完 |
17
drymonfidelia OP @ie88 tauri 只是拿来当套壳浏览器,不能改动现有网页代码
|
18
NessajCN 323 天前
|
19
drymonfidelia OP @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"); } ``` |
20
iorilu 323 天前
一定要牢记, 不要在公司生成环境, 有时间要求时候自作聪明搞不熟得新技术, 省的给领导留下不好印象
|
21
NessajCN 323 天前
@drymonfidelia
你是不是对 tauri 的用法有很大的误解?它不是给你用来当套壳浏览器的,所谓的 js 前端只是个画 ui 的工具,你甚至不能在前端用 fetch 或 axios 这些前端请求工具。 我发你的这段代码是让你生成好 state 后在 rust 后端发请求然后返回给前端显示的。你得在 command 函数里调用 req_client.client.get() |
22
drymonfidelia OP |
23
zeusho871 323 天前 via Android
用 wails ,我在 mac windows 成功了
|
24
drymonfidelia OP |
25
NessajCN 323 天前
@drymonfidelia 我看了一下,是你自己没表达清楚
你标题问的是 「我要做一个专用浏览器」 但你实际的需求是「选一个现成浏览器好方便地显示我们的网页」 你能分清「自己手搓浏览器」和「给自己网页套个现成浏览器的壳」这两者之间的区别吧? |
26
drymonfidelia OP @NessajCN 「我要做一个专用浏览器」应该是比「选一个现成浏览器好方便地显示我们的网页」更底层的需求,我认为是应该更能实现改个默认请求头这种简单需求
|
27
NessajCN 323 天前 via Android 1
@drymonfidelia 确实更能实现啊,我不就用 3 分钟写了实现代码吗
只不过 tauri 它真不是你要的现成浏览器啊。 你要类比,前端 js 在这里的作用完全是 qml 在 qt 里的作用,也就是画个静态页面当 ui 你想拿 tauri 来访问其他网站并且完美的显示在前端 ui ,那你当然得在 rust 里写 get 函数,并且自己重新手动写前端静态显示代码。说到底 tauri 它是个「 Rust gui 」框架而不是浏览器。 |
28
ShadowPower 323 天前
其实两者的用途不太一样……
Electron 适合直接把网页打包成应用,或者以 JavaScript/TypeScript 为主的应用。 而 Tauri 的定位则是为 Rust 程序提供一个界面,只是界面部分使用系统的 WebView 来实现。 |
29
djs 323 天前
专用浏览器用这个?不是应该直接干一个 chromium 下来自己编译吗
|
30
ShadowPower 323 天前
对了,顺便一提,Tauri 的规划里其实还有抛弃 WebView ,自己实现界面绘制,虽然我感觉大概率走不通这条路。
但是可以从这一点看出来,Tauri 的目标和 Electron 其实完全不一样,只是恰巧有一些交集…… |
32
drymonfidelia OP @dcsuibian 我们公司是交代的事情干完了,上班时间看 AV 都没人管你
|
33
nebkad 322 天前 1
这帖子真的太难顶了,浪费了我整整一分钟
|
34
araraloren 322 天前
@nebkad 就是在钓鱼。。
|
35
0x723b 322 天前
如果你的需求是拦截 webview 的请求并添加 header 的话,根据 https://github.com/tauri-apps/tauri/discussions/4690 , 似乎是无法实现的
|
36
drymonfidelia OP @araraloren 看什么都钓鱼 我要钓鱼写这么长代码干什么 能钓鱼的话题多了去了
|
37
lisongeee 322 天前
所以 tauri 到底能不能实现拦截并修改 webview 的任意请求?
有时候需要在 webview 里放置同公司其它组的业务页面,然后拦截加上自定义登录参数 这种需求虽然不敢说不多见但是也不敢说不少见 |
38
rming 322 天前 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 手机随便搜了下,仅供参考
|
39
kkk9 322 天前 1
@lisongeee #37 rust 里写一个类 fetch 函数,js 内替换原来的 fetch ,实际调用的是这个函数。
tauri 调用 webview 的 api 来干活,一切规则需要遵循系统 webview ,并不能自定义或者修改核心 electron 本质上是一个 chromium 浏览器的,提供各种封装好的 API ,支持自定义,可以修改核心 |
40
CLMan 322 天前 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"); } |
41
CLMan 322 天前
@CLMan 需要添加依赖(为了避免兼容性问题,与你使用的 tauri 版本保持一致,可以使用 IDE 的依赖管理功能查看)
[dependencies] webview2-com = "0.19.1" windows = "0.39.0" |
42
Eiden 322 天前 1
op 是懂提问题的艺术的
|
44
winmagic 322 天前 via Android
img src 访问 http 协议,不支持这个问题有遇到过吗,csp 设置了好像不行
|
45
pdxjun 322 天前
放弃 rust 吧,这是个缝合怪,个人感觉,缝合的还不是很好
|
46
NessajCN 322 天前
对了,今天 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" |
47
githmb 322 天前
总结:不想改前端代码
|
48
drymonfidelia OP @githmb 前端代码是其它部门写好的 哪有办法说改就改
|
49
drymonfidelia OP |
50
kkk9 322 天前
@drymonfidelia #49 所以才需要技术选型。这个问题本身就不是 tauri 和 electron 的问题,是用的人有问题。😂
|
51
adoal 322 天前
tauri
是:用 web 前端技术栈开发本机 UI 的框架;不是:嵌入浏览器访问现成网站。 是:支持多个平台运行的本机 UI 框架;不是:避开不同浏览器行为差异的“跨平台”框架。 |
52
CLMan 321 天前 1
@drymonfidelia 我前面给出的方案修复了你代码里面的语法错误,你都不看一眼吗?
|
53
CLMan 321 天前 1
@drymonfidelia 在我本机上实测,可以正确设置 header 。
|
54
drymonfidelia OP @CLMan 谢谢 今天放假了,在路上没有电脑测试
|
55
djkloop 321 天前
@drymonfidelia #32 细说
|
56
wangtian2020 321 天前
看到 electron 又赢了,我就放心了
|
57
secondwtq 321 天前
算是把 Cunningham's Law 玩儿明白了 ...
|
58
wocao666 321 天前
@drymonfidelia 这么爽??我上班学个习,领导看见了都时不时交代点工作给我干了
|
59
iugo 321 天前
可能需求不一样吧, 我们的 Web 没有做服务端渲染, 所以类似需求的实现方式是前端 JS 检查了一些信息后 API 请求到服务器. 而不是在跳转页面的时候修改请求头.
|
60
drymonfidelia OP @CLMan #40 的代码可以用,谢谢
|
61
ungrownxiaohao 307 天前
@roycestevie6761 #3 你好,rust 社区是这样的,争着抢着要“改天换地”
|
62
uLdP4HCJts79jh56 267 天前 via Android
@lisongeee 拦截不能,获取 webview 里的 cookie 也不行,有维护者在 issue 里回复过对 webview 控制力很弱
|
63
seu 242 天前
不行 issue 里面有明确的说过 可能会考虑在 v3 版本添加 现在的技术路线图不包含这块
|