< 返回版块

lithbitren 发表于 2020-10-25 23:17

Tags:actix,json,payload

https://github.com/actix/examples/blob/master/json/src/main.rs

读actix,examples,json的一个范例,菜鸟说说的理解和不解,望大神们指教。

里面70行服务初始化里面,全局限制了json或body的大小为4k,这个好理解。

74行则是为路由的json提交限制了大小为1k,一般可以认为局部变量优先于全局变量,也就是访问这个句柄的时候限制更严格了,应该可以这么理解吧,这里问题也不大。

            .wrap(middleware::Logger::default())
            .data(web::JsonConfig::default().limit(4096)) // line 70 <- limit size of the payload (global configuration)
            .service(web::resource("/extractor").route(web::post().to(index)))
            .service(
                web::resource("/extractor2")
                    .data(web::JsonConfig::default().limit(1024)) // line 74 <- limit size of the payload (resource level)
                    .route(web::post().to(extract_item)),
            )
            .service(web::resource("/manual").route(web::post().to(index_manual))) // line 77

但是77行对应的路由函数就不太明白了,这里全局变量标记了一个大小单独限制这个路由的载荷,这里的限制和全局web::JsonConfig会冲突吗,怎么冲突的,优先级是怎么判定的?

在句柄的参数里面添加了载荷参数payload,33行用一个byte数组来接受payload(其实这里不太理解为什么actix要单独把&[u8]单独作为类型放进框架里面,不过这个问题不是很重要)。

然后协程循环读取载荷,这里的疑问是web::Payload类型算是真正的流式数据吗?

在运行这个函数时候payload的内容已经全部被服务器接收还是只接受了部分,是像tokio和async-std的简易TcpListener范例那样存入一个1024大小的buf里还是怎么接受的?

chunk块的大小chunk.len()是怎么确定的,是固定的吗?

35行为啥要重新声明chunk并加一个try问号,这里会产生什么样的异常?

const MAX_SIZE: usize = 262_144; // max payload size is 256k

/// This handler manually load request payload and parse json object
async fn index_manual(mut payload: web::Payload) -> Result<HttpResponse, Error> {
    // payload is a stream of Bytes objects
    let mut body = web::BytesMut::new(); // line 33
    while let Some(chunk) = payload.next().await {
        let chunk = chunk?; // line 35
        // limit max size of in-memory payload
        if (body.len() + chunk.len()) > MAX_SIZE {
            return Err(error::ErrorBadRequest("overflow"));
        }
        body.extend_from_slice(&chunk);
    }

    // body is loaded, now we can deserialize serde-json
    let obj = serde_json::from_slice::<MyObj>(&body)?; // line 44
    Ok(HttpResponse::Ok().json(obj)) // <- send response
}

44行的serde_json::from_slice,51行json::parse虽然可以理解是serde_json和json库的函数,但好像也没use出来啊,为啥就能用了呢,这两个json库都挺常见的,有啥区别呢?

还有futures::StreamExt这个库声明了下文也没用上,是做啥的?

actix的examples功能基本都能看明白,复现似乎也不难,但碍于对rust的理解太浅,很多零碎肤浅的细节搞不清楚原理。读源码算是个方法,但一个完整的大框架来说对于我这个新手来说还是难度太高了。尽管似乎都不太影响实现,但还望大佬们指教解惑


Ext Link: https://github.com/actix/examples/blob/master/json/src/main.rs

评论区

写评论
作者 lithbitren 2020-10-26 16:11

太谢谢辣,这么多疑惑一次性大丰收

--
👇
fakeshadow: 不冲突,Resource/Scope或者任何你自己写的Service都可以有个单独的extension容器,这个容器在提取的时候会被优先调用。

是。Payload是tokio TcpStream上的抽象,由一个Dispatcher类型来异步读取TcpStream并填充Payload。

因为是基于tokio的,所以可对照tokio。

chunk的大小一般在4-32k之间。(不确认可能有误)

返回错误错误。Payload默认的流Item类型是Result<Bytes, Error>。

可以这样使用。serde是序列化的抽象库,它不仅支持json这一个格式。serde_json则是专门处理json格式的,一个类型只要实现了serde的(De)Serialize,都可以用serde_json来(反)序列化。

作者 lithbitren 2020-10-26 16:09

原来如此,谢谢解惑

--
👇
umaYnit: futures::StreamExt是一个trait,34行payload的next()方法就是它提供的

fakeshadow 2020-10-26 14:04

不冲突,Resource/Scope或者任何你自己写的Service都可以有个单独的extension容器,这个容器在提取的时候会被优先调用。

是。Payload是tokio TcpStream上的抽象,由一个Dispatcher类型来异步读取TcpStream并填充Payload。

因为是基于tokio的,所以可对照tokio。

chunk的大小一般在4-32k之间。(不确认可能有误)

返回错误错误。Payload默认的流Item类型是Result<Bytes, Error>。

可以这样使用。serde是序列化的抽象库,它不仅支持json这一个格式。serde_json则是专门处理json格式的,一个类型只要实现了serde的(De)Serialize,都可以用serde_json来(反)序列化。

uno 2020-10-26 09:38

futures::StreamExt是一个trait,34行payload的next()方法就是它提供的

1 共 4 条评论, 1 页