You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Axum实现点击按钮生成服务器文件并本地下载的技术问询

实现步骤指导

1. 生成带下载按钮的HTML页面

把原check_files函数改为返回HTML页面,让用户能直观看到两个下载按钮,按钮点击后跳转至专门的下载接口:

use axum::response::Html;
// 保留原有其他引入

async fn check_files(Path(run_number): Path<u32>) -> Html<String> {
    let html = format!(
        r#"
        <html>
            <body>
                <h1>Download Files for Run {run_number}</h1>
                <button onclick="location.href='/download/csv/{run_number}'">Download csv</button>
                <button onclick="location.href='/download/txt/{run_number}'">Download txt</button>
            </body>
        </html>
        "#
    );
    Html(html)
}

2. 添加下载处理路由

在main函数中新增下载相关路由,分别对应csv和txt文件的下载请求:

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(|| async { "Hello, World!" }))
        .route("/:run_number", get(check_files))
        // 新增下载路由
        .route("/download/csv/:run_number", get(download_csv))
        .route("/download/txt/:run_number", get(download_txt));

    let listener = tokio::net::TcpListener::bind("127.0.0.1:8080")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

3. 实现核心下载逻辑

编写通用处理函数,完成文件存在性检查、外部命令生成文件、返回下载响应三个核心步骤:

use axum::response::{NamedFile, IntoResponse};
use tokio::process::Command;
use std::path::Path;

// 通用下载处理,接受文件后缀参数
async fn download_file(run_number: u32, ext: &str) -> Result<impl IntoResponse, String> {
    let file_path = format!("{run_number}.{ext}");
    let path = Path::new(&file_path);

    // 文件不存在则执行外部命令生成
    if !path.exists() {
        let status = Command::new("touch")
            .arg(&file_path)
            .status()
            .await
            .map_err(|e| format!("执行生成命令失败: {}", e))?;
        
        if !status.success() {
            return Err(format!("命令执行失败,状态码: {}", status));
        }
    }

    // 返回文件下载,设置响应头触发浏览器下载行为
    NamedFile::open(path)
        .await
        .map(|file| file.with_header(("Content-Disposition", format!("attachment; filename=\"{file_path}\""))))
        .map_err(|e| format!("打开文件失败: {}", e))
}

// 封装csv文件下载处理
async fn download_csv(Path(run_number): Path<u32>) -> impl IntoResponse {
    download_file(run_number, "csv").await
}

// 封装txt文件下载处理
async fn download_txt(Path(run_number): Path<u32>) -> impl IntoResponse {
    download_file(run_number, "txt").await
}

4. 补充依赖配置

确保Cargo.toml中包含所需依赖:

[dependencies]
axum = "0.7"
tokio = { version = "1.0", features = ["full"] }

关键注意事项

  • 异步命令执行:必须使用tokio::process::Command而非std::process::Command,避免阻塞Axum的事件循环影响服务性能。
  • 错误处理:示例用简单字符串返回错误,实际项目可结合Axum的StatusCode和自定义错误类型优化用户体验。
  • 安全防护:若服务需暴露公网,要验证run_number的合法性,防止路径遍历或恶意命令执行风险。

内容的提问来源于stack exchange,提问作者DJDuque

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 15:27:25