更新一下:FormData确实很好用,不用刷新网页的情况下,可以直接完成我要的功能!
就是和warp搭配起来,有点麻烦。
loadDom.onclick = function () {
if (filesDom.value != "") {
var url = 'http://127.0.0.1:3030/';
var formData = new FormData();
loadedFile = filesDom.value;
formData.append("load", loadedFile);
var request = new XMLHttpRequest();
request.open("POST", url);
request.onload = function() {
if (request.readyState === request.DONE) {
if (request.status == 200) {
let response = request.responseText.split("\r\n");
let ew = JSON.parse( response[0] );
let yy = JSON.parse( response[1] );
for (var i = 0; i < ew.length; i++) {
ewValue[i].value = ew[i];
yyValue[i].value = yy[i];
}
}
}
};
request.send(formData);
}
}
rust做如下处理
#[tokio::main]
async fn main() {
let default_reply2 = warp::path::end().and(warp::get()).map(|| Response::builder().body(default_reply()));
let post_reply = warp::post()
.and(warp::multipart::form())
.and_then(post_reply);
let routers = warp::get().and(default_reply2).or(post_reply);
warp::serve(routers).run(([127, 0, 0, 1], 3030)).await;
}
async fn post_reply(form: warp::multipart::FormData) -> Result<impl warp::Reply, warp::Rejection> {
let mut parts: Vec<warp::multipart::Part> = form
.try_collect()
.await
.map_err(|_e| warp::reject::reject())?;
if parts[0].name() == "save" {
//....
} else {
//....
let response_string = read_setting();
Ok(Response::builder().body(response_string))
}
}
评论区
写评论我直接在svelte里加
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css">
,bulma挺好用的。颜值又上升了不少。wasm我之前有过一遍官方的书。但是应该不会考虑用它,因为我想做的是WEB界面,RUST计算的本地个人用server,计算密集型的部分全部由服务器承压,不太需要wasm的提速。感谢大佬的建议!
--
👇
c5soft: 前端Svelte搭配Typescript,无惧大型应用。前端引入css框架,比如bulma,ui搞定,想要扫二维码吗? 上wasm!
前端Svelte搭配Typescript,无惧大型应用。前端引入css框架,比如bulma,ui搞定,想要扫二维码吗? 上wasm!
感谢大佬的回答,我一步步地在实践这些代码。这两天有空的时候在学svelte,确实好用。目前尝试着做了一个登录界面,尝试着用进去
bind
和dom event
,实用!生成的代码量也少。但svelete的build貌似有点问题?WINDOWS系统下,我直接
npm run dev
可以,但build之后index.html
一直打开是空白,后来把<script defer src='/build/bundle.js'></script>
改成<script defer src='./build/bundle.js'></script>
就成功了。svelte的问题解决了,静态文件服务就也解决了,warp调用静态文件本来我之间就是实践过的。之后几天看看大佬给的multipart的例子,感谢感谢!
我之前一直都是写无UI程序,rust也没有合适的gui库可以用,准备放弃gui转而用web写一点自己用得到的或者有意思的程序了。
--
👇
c5soft: 这段代码启用 Warp的静态文件服务:
静态文件目录Svelte输出目录
好吧 还是谢谢
--
👇
c5soft: 抱歉,tide没用过
--
👇
tokyohuang123: tide的 multipart怎么写 大佬
--
👇
c5soft: 如果上传文件,比如写FilePond的服务端,需要用到multipart/form-data,Warp核心代码这样写:
客户端通过 POST /api/upload调用,实例代码的上传文件大小限制为1GB
抱歉,tide没用过
--
👇
tokyohuang123: tide的 multipart怎么写 大佬
--
👇
c5soft: 如果上传文件,比如写FilePond的服务端,需要用到multipart/form-data,Warp核心代码这样写:
客户端通过 POST /api/upload调用,实例代码的上传文件大小限制为1GB
tide的 multipart怎么写 大佬
--
👇
c5soft: 如果上传文件,比如写FilePond的服务端,需要用到multipart/form-data,Warp核心代码这样写:
客户端通过 POST /api/upload调用,实例代码的上传文件大小限制为1GB
哈哈
--
👇
c5soft: 这段代码启用 Warp的静态文件服务:
静态文件目录Svelte输出目录
这段代码启用 Warp的静态文件服务:
静态文件目录Svelte输出目录
核心代码放在service.rs文件中,主程序main.rs这样写:
系统参数设置AppContext放在配置文件比如config.json中,服务启动时一次读取,用JSON格式传递到下级函数中去。AppContext里可以放置任何东西,比如数据库连接缓存池Pool等等。
如果上传文件,比如写FilePond的服务端,需要用到multipart/form-data,Warp核心代码这样写:
客户端通过 POST /api/upload调用,实例代码的上传文件大小限制为1GB
感谢你的建议!我尝试着用FormData,前端部分确实很容易。
但是,有个问题就是warp处理起来非常麻烦。我使用
multipart::FormData
处理,尝试了半个小时,没有成功,而且相关资料太少了。尝试body
系列的,只有bytes
能成功,但是处理起来一样很麻烦,解码后是一大串字符串,包含一串数字,然后是content-disposition,然后是name=...\r\n\r\n...(key)...\r\n--------------。远不如之前解码后"save=...&&ew=....."这种来得方便啊。用warp的multipart貌似要处理
Futures::Stream
,挺麻烦的样子。之前那个代码是抄的,FormData相比那个有什么特殊优势吗?
--
👇
viruscamp: 1. 你前端那块代码最好用 FormData 对象的使用 很容易用的
你前端那块代码最好用 FormData 对象的使用 很容易用的
read 的问题跟http和tcp关系都不大,要学会 stream(输入流) 的用法,而这种用法,c c++ java node 都差不多。 一次的 read 是不保证返回你要的所有数据的,给再大的 buffer 都不保证,所以它的返回值一定要用。
--
👇
eweca-d: http协议还真是复杂呢。感谢让我又知道了一些web相关的知识。
现在看来,确实用一些现成的框架可以避免很多麻烦。虽然缺点就是没系统学习过web编程的,用完框架之后经常是知其然而不知其所以然就是了。
--
👇
Aya0wind: 不是有长度限制,而是因为tcp的特性,一端一次send的内容,在另一端只用一次read可能读不完,需要多次read。能读多少是一个未知数,所以你要通过读到的http协议规定的终止符才能判断读完了一个完整的http请求,而不是仅仅read一次就以为自己已经把对方send的东西全部读完了。
谢谢你的耐心回复!哈哈,之后我会好好看看这个。然后看看是不是整个重构下这个小工具来练练手。
--
👇
c5soft: 不知道如何用warp可以看看这个帖子:https://rustcc.cn/article?id=0e8e1b38-5180-4021-b6fe-e017eb8ff315 好多资料到收集在这里: How to use Rust Warp
Creating a REST API in Rust with warp
Create an async CRUD web service in Rust with warp
How do I inject dependencies into my route handlers in Warp?
如何使用Warp来处理通过http头传送认证信息
不知道如何用warp可以看看这个帖子:https://rustcc.cn/article?id=0e8e1b38-5180-4021-b6fe-e017eb8ff315 好多资料到收集在这里: How to use Rust Warp
Creating a REST API in Rust with warp
Create an async CRUD web service in Rust with warp
How do I inject dependencies into my route handlers in Warp?
如何使用Warp来处理通过http头传送认证信息
http协议还真是复杂呢。感谢让我又知道了一些web相关的知识。
现在看来,确实用一些现成的框架可以避免很多麻烦。虽然缺点就是没系统学习过web编程的,用完框架之后经常是知其然而不知其所以然就是了。
--
👇
Aya0wind: 不是有长度限制,而是因为tcp的特性,一端一次send的内容,在另一端只用一次read可能读不完,需要多次read。能读多少是一个未知数,所以你要通过读到的http协议规定的终止符才能判断读完了一个完整的http请求,而不是仅仅read一次就以为自己已经把对方send的东西全部读完了。
不是有长度限制,而是因为tcp的特性,一端一次send的内容,在另一端只用一次read可能读不完,需要多次read。能读多少是一个未知数,所以你要通过读到的http协议规定的终止符才能判断读完了一个完整的http请求,而不是仅仅read一次就以为自己已经把对方send的东西全部读完了。
👇
eweca-d: 你的意思是,tecpstream的read是有长度限制的,就算是我的buffer再大,也会因此而被截断。所以需要再次read或者read_to_end是吗?
有道理,我尝试了下二次读取到buffer2里,成功在buffer2得到了内容。
但是又遇到了问题,假如我在第一次读取stream完毕后,第二次读取stream内没有内容,那么我的stream.write和stream.flush就会失效。怀疑是服务器会第二次尝试读取时遇不到EOF,然后无限等待。所以每次read都要判断是否读到末尾,我不知道rust或者http协议里是怎么判断的,但是我看到的buffer里,在我的所有内容后直接就是\u{0}了。
由于buffer尺寸和tcpstream的read最大尺寸不同,不管读没读完后面都是一大串\u{0}。那么我能想到的办法就是在post最后加一个end=true,每次read之后解码看是否包含end=true,不包含则read到包含为止。
最后成功解决了问题!web编程真是复杂啊。
--
👇
Aya0wind: 抛开rust,我猜是因为tcp提供的最基本的read函数,是无法指定一次读的长度,只能指定最大长度的(rust的tcpstream也是如此)。也就是说一次read可能并不会把对方本次发送的所有内容读完,也有人把这个现象称作tcp粘包。本质上是因为tcp并不是包式协议,而是流式协议,如果需要分包,需要上层规定另外的分包协议。 而你这里使用read,如果一次发送的长度比较长,那么一次read读不完,所以你就会发现header是断的。 解决方法就是严格按照http协议来,首先去了解http协议是怎么分隔各个部位的,一次read后判断没有读到末尾,就需要继续调用read。
你的意思是,tecpstream的read是有长度限制的,就算是我的buffer再大,也会因此而被截断。所以需要再次read或者read_to_end是吗?
有道理,我尝试了下二次读取到buffer2里,成功在buffer2得到了内容。
但是又遇到了问题,假如我在第一次读取stream完毕后,第二次读取stream内没有内容,那么我的stream.write和stream.flush就会失效。怀疑是服务器会第二次尝试读取时遇不到EOF,然后无限等待。所以每次read都要判断是否读到末尾,我不知道rust或者http协议里是怎么判断的,但是我看到的buffer里,在我的所有内容后直接就是\u{0}了。
由于buffer尺寸和tcpstream的read最大尺寸不同,不管读没读完后面都是一大串\u{0}。那么我能想到的办法就是在post最后加一个end=true,每次read之后解码看是否包含end=true,不包含则read到包含为止。
最后成功解决了问题!web编程真是复杂啊。
--
👇
Aya0wind: 抛开rust,我猜是因为tcp提供的最基本的read函数,是无法指定一次读的长度,只能指定最大长度的(rust的tcpstream也是如此)。也就是说一次read可能并不会把对方本次发送的所有内容读完,也有人把这个现象称作tcp粘包。本质上是因为tcp并不是包式协议,而是流式协议,如果需要分包,需要上层规定另外的分包协议。 而你这里使用read,如果一次发送的长度比较长,那么一次read读不完,所以你就会发现header是断的。 解决方法就是严格按照http协议来,首先去了解http协议是怎么分隔各个部位的,一次read后判断没有读到末尾,就需要继续调用read。
抛开rust,我猜是因为tcp提供的最基本的read函数,是无法指定一次读的长度,只能指定最大长度的(rust的tcpstream也是如此)。也就是说一次read可能并不会把对方本次发送的所有内容读完,也有人把这个现象称作tcp粘包。本质上是因为tcp并不是包式协议,而是流式协议,如果需要分包,需要上层规定另外的分包协议。 而你这里使用read,如果一次发送的长度比较长,那么一次read读不完,所以你就会发现content是断的。 解决方法就是严格按照http协议来,首先去了解http协议是怎么分隔各个部位的,一次read后判断没有读到末尾,就需要继续调用read。
我现在服务器端口是这样的:
default_reply()
会读取html模板并进行一定的修改作为html格式的String
来返回从而构建出网页,而post
返回的主体里根据使用者传到服务器参数,也是读取html模板并进行一定的修改作为html格式的String
来返回从而构建出网页。之前我是用std的stream.write()
和stream.flush()
来完成这个功能。我的理解是,这个就是静态文件服务吧?
用svelte重写页面这个建议,我会认真考虑下的!这两天可以先了解下svelte,技多不压身。感谢!
👇
c5soft: 再把页面用svelte重写一下,warp里启用静态文件服务,立马高大上。exe文件大小根本不是问题,我生产环境,warp+reqwest+tiberius, msvc 64比特, 9MB。
再把页面用svelte重写一下,warp里启用静态文件服务,立马高大上。exe文件大小根本不是问题,我生产环境,warp+reqwest+tiberius, msvc 64比特, 9MB。