如何在Rust(tokio+axum)中将genpdf生成的PDF返回给客户端?
解决genpdf生成PDF流式返回给Axum客户端的问题
原代码存在的问题
Reade是拼写错误,应为ReaderStreamdoc.render(w)中的w未定义,genpdf的render需要一个实现std::io::Write的对象HeaderMap创建后未声明为可变,直接insert会报错- 函数返回类型与内部
Ok分支不匹配,缺少错误处理的返回逻辑
修正后的完整代码
use axum::{ http::{header, HeaderMap, HeaderValue}, response::{IntoResponse, StreamBody}, }; use genpdf::{elements::Text, fonts::from_files, Document, SimplePageDecorator}; use std::io::Cursor; use tokio_util::io::ReaderStream; async fn make_pdf() -> Result<impl IntoResponse, Box<dyn std::error::Error>> { // 加载字体文件 let font_family = from_files("./fonts", "Calibri", None) .expect("Failed to load font"); // 构建PDF文档结构 let mut doc = Document::new(font_family); doc.set_title("Test Title"); let mut decorator = SimplePageDecorator::new(); decorator.set_margins(10); doc.set_page_decorator(decorator); doc.push(Text::new("First PDF Text")); // 将PDF渲染到内存缓冲区 let mut pdf_data = Vec::new(); doc.render(&mut pdf_data)?; // 将内存数据转换为异步可读流 let cursor = Cursor::new(pdf_data); let stream = ReaderStream::new(cursor); // 设置响应头,指定文件类型和下载属性 let mut headers = HeaderMap::new(); headers.insert( header::CONTENT_TYPE, HeaderValue::from_static("application/pdf"), ); headers.insert( header::CONTENT_DISPOSITION, HeaderValue::from_static("attachment; filename=\"Cargo.pdf\""), ); // 返回带响应头的流式响应 Ok((headers, StreamBody::new(stream))) }
关键修改说明
- 用
Vec<u8>作为内存缓冲区接收PDF渲染结果,避免额外文件IO开销 - 通过
Cursor<Vec<u8>>将静态内存数据转换为AsyncRead实现,适配ReaderStream的异步流要求 - 声明
mut headers以支持插入响应头字段 - 修正函数返回类型为
Result,统一处理渲染和类型转换中的错误 - 使用
HeaderValue::from_static简化响应头创建,避免字符串解析错误
内容的提问来源于stack exchange,提问作者Luck Proit
相关产品推荐
相关产品推荐

