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

如何在基于Trunk的Rust Web应用中访问已复制的JSON资产文件?

如何在基于Trunk的Rust Web应用中访问已复制的JSON资产文件?

嘿,这个问题我之前也碰到过!核心原因是你混淆了原生Rust和Wasm环境的文件访问方式——当你的代码编译成Wasm运行在浏览器里时,std::fs这套API完全不适用,因为浏览器沙箱不允许直接访问文件系统,这就是为什么你的App会卡住。下面给你几个实用的解决方案:

方案1:直接通过网络请求加载单个已知文件

如果你的JSON文件路径是提前确定的,最直接的方式是用HTTP请求来加载它们。你可以用reqwest(要启用Wasm支持)或者web-sys的原生fetch API来实现。

举个用reqwest的例子:

use reqwest::Client;
use serde::Deserialize;

// 定义你的JSON数据结构
#[derive(Deserialize, Debug)]
struct AppConfig {
    app_name: String,
    version: String,
}

async fn load_config() -> Result<AppConfig, reqwest::Error> {
    // 创建reqwest客户端
    let client = Client::new();
    // 发送请求到Trunk复制后的资产路径
    let response = client.get("/assets/data/config.json").send().await?;
    // 解析JSON到结构体
    let config = response.json().await?;
    Ok(config)
}

注意要确保你的Trunk.toml里正确配置了copy-dir,比如:

[[assets]]
kind = "copy-dir"
source = "assets/data"
target = "assets/data"

这样Trunk会把本地assets/data目录复制到构建产物里,浏览器就能通过/assets/data/xxx.json访问到文件。

方案2:生成文件清单来遍历目录中的所有JSON

如果需要遍历整个目录下的JSON文件,浏览器本身没有直接遍历远程目录的API,这时候可以借助构建脚本提前生成文件清单:

  1. 编写build.rs脚本,扫描本地资产目录并生成包含所有JSON路径的Rust常量:
use std::fs;
use std::path::Path;

fn main() {
    // 指向你的本地JSON资产目录
    let json_dir = Path::new("assets/data");
    let mut json_files = Vec::new();

    // 遍历目录下的所有JSON文件
    for entry in fs::read_dir(json_dir).expect("Failed to read assets directory") {
        let entry = entry.expect("Failed to read directory entry");
        let path = entry.path();
        // 筛选出JSON文件
        if path.extension().unwrap_or_default() == "json" {
            // 转换为浏览器可访问的路径
            let relative_path = path.strip_prefix("assets").unwrap().to_str().unwrap();
            json_files.push(format!("/assets{}", relative_path));
        }
    }

    // 生成Rust文件,导出文件列表常量
    fs::write(
        "src/json_assets.rs",
        format!("pub const JSON_FILES: &[&str] = &{:?};", json_files),
    ).expect("Failed to write JSON assets list");

    // 告诉Cargo:如果资产目录变化,重新运行构建脚本
    println!("cargo:rerun-if-changed=assets/data");
}
  1. 在你的主代码中引入这个常量,逐个加载所有JSON文件:
// 引入生成的文件清单
mod json_assets;
use json_assets::JSON_FILES;
use reqwest::Client;
use serde_json::Value;

async fn load_all_json() -> Result<Vec<Value>, reqwest::Error> {
    let client = Client::new();
    let mut all_data = Vec::new();

    // 遍历所有文件路径,逐个加载
    for file_path in JSON_FILES {
        let response = client.get(file_path).send().await?;
        let data = response.json().await?;
        all_data.push(data);
    }

    Ok(all_data)
}

方案3:将JSON直接嵌入到Wasm二进制中

如果你的JSON文件比较小,不需要动态更新,也可以直接把它们嵌入到Wasm里,这样不需要网络请求就能访问:

use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct StaticData {
    items: Vec<String>,
}

fn load_embedded_data() -> StaticData {
    // 直接嵌入本地JSON文件内容
    let json_content = include_str!("../../assets/data/static.json");
    // 解析为结构体
    serde_json::from_str(json_content).expect("Failed to parse embedded JSON")
}

这种方式的好处是加载速度快,不需要依赖网络,但缺点是如果JSON文件更新,你需要重新编译Wasm。

备注:内容来源于stack exchange,提问作者adamconkey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:17:58