Rust Actix-web如何解析XML上传 serde-xml-rs库的应用

3次阅读

Actix-web无法直接用web::json处理xml请求,因其硬编码只认application/json;需手动读取body字节并用serde_xml_rs::from_reader解析,注意同步解析、字段重命名及Content-Type校验。

Rust Actix-web如何解析XML上传 serde-xml-rs库的应用

Actix-web 接收 XML 请求体时为何不能直接用 web::Json

因为 web::Json 内部硬编码依赖 serde_json,只认 Content-Type: application/json,且会自动拒绝非 JSON MIME 类型。XML 请求(application/xmltext/xml)会被直接拦截并返回 400 错误 —— 这不是配置问题,是类型守门员的强制策略。

必须绕过默认 extractor,手动读取原始 body 并用 serde_xml_rs 解析。

如何用 serde_xml_rs 解析 Actix-web 的 XML body?

核心步骤:禁用自动解析 → 读取完整字节流 → 用 serde_xml_rs::from_reader 解析。注意两点:一是 serde_xml_rs 不支持异步 reader,所以必须先 .await 收完全部 body;二是它默认不处理 XML 声明(如 ),但实际能容忍,无需提前 strip。

  • 确保 Struct 字段加 #[serde(rename = "xxx")] 匹配 XML tag 名(大小写、中划线敏感)
  • 嵌套元素用结构体字段,文本内容用 #[serde(rename = "$value")]
  • 可选字段用 Option,缺失标签会被反序列化为 None
  • 数组用 Vec,前提是 XML 中有多个同名 tag(serde_xml_rs 自动聚合)
use serde::Deserialize; use actix_web::{web, httpResponse, HttpRequest, HttpError}; use serde_xml_rs;  #[derive(Deserialize, Debug)] struct User {     #[serde(rename = "user_id")]     id: u32,     #[serde(rename = "full-name")]     full_name: String,     #[serde(rename = "$value")]     content: Option, }  async fn handle_xml(req: HttpRequest, body: web::Bytes) -> Result {     let user: User = serde_xml_rs::from_reader(body.as_ref())         .map_err(|e| HttpError::BadRequest(e.to_string()))?;     Ok(HttpResponse::Ok().json(user)) }

Content-Type 不匹配导致解析失败的常见表现

如果客户端发的是 text/xml,而你代码里没校验或没适配,serde_xml_rs 本身不会报 MIME 错误,但 Actix-web 可能在中间件或 CORS 预检阶段就拦掉请求。更隐蔽的问题是:某些 HTTP 客户端(如 curl)默认不带 Content-Type,此时 Actix-web 会 fallback 到 application/octet-stream,body 虽能读到,但语义已丢失 —— 你需要显式检查 req.headers().get("content-type")

  • 推荐在 handler 开头加校验:if req.content_type() != "application/xml" && req.content_type() != "text/xml" { return Err(HttpError::UnsupportedMediaType(...)); }
  • req.content_type() 返回的是 Option,需用 .and_then(|v| v.to_str().ok()) 安全转换
  • 测试时用 curl 发送:curl -X POST -H "Content-Type: application/xml" --data-binary @input.xml http://localhost:8080/xml

为什么不用 quick-xml 替代 serde_xml_rs

serde_xml_rs 是唯一与 serde 生态无缝对接的 XML 库,支持标准 derive 宏;quick-xml 更快、更底层,但需要手写事件循环或绑定到 serdeDeserializer 实现 —— 对多数业务场景属于过度设计。除非你处理 GB 级 XML 流或需要 SAX 式逐节点处理,否则坚持用 serde_xml_rs 更稳。

另外注意:serde_xml_rs 目前不支持 Namespace(如 ),若接口协议含 namespace,就得切到 quick-xml + 手动映射,这是最容易被忽略的兼容性断点。

text=ZqhQzanResources