Rust Wasm中web_sys::create_object_url_with_blob二进制数据格式错误如何解决
问题原因
你遇到的异常由两个核心错误导致:
- 错误使用
js_sys::Uint8Array::view创建临时不安全视图:该方法得到的Uint8Array仅持有Wasm线性内存的裸指针,不会拷贝数据,一旦Rust侧的bytes变量被释放、移动,JS侧拿到的内存地址就会指向无效数据,最终Blob拿到的是乱码内容。 - Blob构造参数类型不匹配:
Blob::new_with_u8_array_sequence_and_options的第一个参数要求传入u8数组的集合(对应JS侧包含多个Uint8Array的数组对象),你直接传入单个Uint8Array会被Blob识别为字符串类型,所以会把字节序列作为明文写入文件。
base64方案能正常工作是因为编码后得到的是ASCII字符串,不存在类型匹配和内存有效性的问题,但编码过程会增加33%的数据体积,大文件下编解码开销极高,不适用于大体积文件/多文件场景。
正确实现
let bytes: Vec<u8> = load_file_as_bytes("mydoc.docx"); // 将Rust字节数组拷贝到JS侧的Uint8Array,避免临时视图的内存安全问题 let uint8arr = js_sys::Uint8Array::from(bytes.as_slice()); // 构造符合Blob接口要求的u8数组序列 let arr_sequence = js_sys::Array::new(); arr_sequence.push(&uint8arr); // 生成Blob和下载链接 let blob = web_sys::Blob::new_with_u8_array_sequence_and_options( &arr_sequence, web_sys::BlobPropertyBag::new().type_("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), ).unwrap(); let download_url = web_sys::Url::create_object_url_with_blob(&blob).unwrap();
可选优化(大文件场景)
如果处理的是体积很大的docx文件,不想全量拷贝字节到JS侧,可以手动从Wasm内存中切出指定区间的Buffer,需要自己保证在Blob构造完成前,Rust侧的bytes变量不会被释放:
let bytes: Vec<u8> = load_file_as_bytes("mydoc.docx"); let uint8arr = unsafe { let mem = wasm_bindgen::memory().dyn_into::<js_sys::WebAssembly::Memory>().unwrap().buffer(); js_sys::Uint8Array::new_with_byte_offset_and_length( &mem, bytes.as_ptr() as u32, bytes.len() as u32 ) }; // 后续构造Blob的逻辑和上面一致,构造完成后再丢弃bytes即可
内容的提问来源于stack exchange,提问作者Charles Schleich
相关产品推荐
相关产品推荐

