为何Axum v0.7中的Stream不再实现Sync trait?
Axum v0.7升级后文件上传编译错误原因分析
问题背景
在使用Axum v0.6时,可通过以下代码调用要求Pin<Box<(dyn AsyncRead + Send + Sync)>>参数的create_file函数实现文件上传:
pub async fn create_file( &self, name: &str, reader: Pin<Box<(dyn AsyncRead + Send + Sync)>>, ) -> Result<CreatedFile>
Axum v0.6处理器代码:
// axum's handler pub async fn upload(stream: BodyStream) -> Result<Response, StatusCode> { let stream = stream.map_err(|err| io::Error::new(io::ErrorKind::Other, err)); let res = file_create("filename", Box::pin(StreamReader::new(stream))).await?; Ok((StatusCode::CREATED, "Ok").into_response()) }
升级到Axum v0.7后,修改处理器代码为:
// axum's handler pub async fn upload(request: Request) -> Result<Response, StatusCode> { let stream = request .into_body() .into_data_stream() .map_err(|err| io::Error::new(io::ErrorKind::Other, err)); let res = file_create("filename", Box::pin(StreamReader::new(stream))).await?; Ok((StatusCode::CREATED, "Ok").into_response()) }
此时出现编译错误:
error[E0277]: `(dyn axum::body::HttpBody<Data = tokio_util::bytes::Bytes, Error = axum::Error> + std::marker::Send + 'static)` cannot be shared between threads safely | 59 | Box::pin(StreamReader::new(stream)), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn axum::body::HttpBody<Data = tokio_util::bytes::Bytes, Error = axum::Error> + std::marker::Send + 'static)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn axum::body::HttpBody<Data = tokio_util::bytes::Bytes, Error = axum::Error> + std::marker::Send + 'static)` = note: required for `std::ptr::Unique<(dyn axum::body::HttpBody<Data = tokio_util::bytes::Bytes, Error = axum::Error> + std::marker::Send + 'static)>` to implement `std::marker::Sync` note: required because it appears within the type `Box<dyn HttpBody<Data = Bytes, Error = Error> + Send>` | 195 | pub struct Box< | ^^^ note: required because it appears within the type `Pin<Box<dyn HttpBody<Data = Bytes, Error = Error> + Send>>` | 410 | pub struct Pin<P> { | ^^^ note: required because it appears within the type `UnsyncBoxBody<Bytes, Error>` | 17 | pub struct UnsyncBoxBody<D, E> { | ^^^^^^^^^^^^^ note: required because it appears within the type `Body` | 39 | pub struct Body(BoxBody); | ^^^^ note: required because it appears within the type `BodyDataStream` | 140 | pub struct BodyDataStream { | ^^^^^^^^^^^^^^ note: required because it appears within the type `IntoStream<BodyDataStream>` | 12 | pub struct IntoStream<St> { | ^^^^^^^^^^ note: required because it appears within the type `Map<IntoStream<BodyDataStream>, MapErrFn<{closure@file.rs:48:18}>>` | 15 | pub struct Map<St, F> { | ^^^ note: required because it appears within the type `MapErr<BodyDataStream, {closure@file.rs:48:18}>` | 63 | MapErr<St, F>( | ^^^^^^ note: required because it appears within the type `StreamReader<MapErr<BodyDataStream, {closure@file.rs:48:18}>, Bytes>` | 156 | pub struct StreamReader<S, B> { | ^^^^^^^^^^^^ = note: required for the cast from `Pin<Box<StreamReader<MapErr<BodyDataStream, {closure@file.rs:48:18}>, Bytes>>>` to `std::pin::Pin<std::boxed::Box<(dyn tokio::io::AsyncRead + std::marker::Send + std::marker::Sync + 'static)>>`
错误原因
- Axum v0.7的Body类型变更:Axum v0.7默认使用
UnsyncBoxBody作为Body的底层实现,该类型仅实现了Sendtrait,未实现Synctrait,意味着它无法安全地在线程间共享。 - 数据流的Sync特性缺失:调用
request.into_body().into_data_stream()得到的BodyDataStream,内部依赖未实现Sync的Body类型,导致整个数据流不满足Sync要求。 - 类型匹配失败:
create_file函数要求参数必须同时满足AsyncRead + Send + Sync,但通过StreamReader包装后的数据流仅具备AsyncRead + Send特性,缺少Sync,因此无法完成类型转换,触发编译错误。 - v0.6与v0.7的差异:Axum v0.6中的
BodyStream内部实现满足Send + Sync,因此当时的代码可以正常编译;v0.7改用非线程安全的UnsyncBoxBody作为默认Body,直接导致了该兼容性问题。
内容的提问来源于stack exchange,提问作者Fred Hors
相关产品推荐
相关产品推荐

