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

通过Axios发送PDF至Actix Web遇解析错误,求解决方案

问题描述

我用NextJS开发时遇到PDF上传解析问题,流程及代码如下:

1. NextJS前端调用内部API

...
mutateUser(
  await fetchJson("/path/to/api", {
    method: "POST",
    headers: { "Content-Type": "application/pdf" },
    body: file, // const [file, setFile] = useState<File | null>(null);
  })
);
...

2. Next内部API通过Axios调用Actix Web服务器

...
const { token } = req.session.user;
const body = req.body;
const api_url = `${process.env.SERVER_API_URL}/path/to/api` as string;
console.log(body.length);

try {
  const response = await axios.post(api_url, body, {
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/pdf",
    },
  });
  res.json({ ...response.data, isLoggedIn: true });
}
...

3. Actix Web端处理逻辑

pub async fn route_function(db: Data<DatabaseRepository>, mut payload: Payload, auth: AuthorizationService) -> HttpResponse {
    let id = auth.id;
    let mut bytes = BytesMut::new();
    while let Some(item) = payload.next().await {
        bytes.extend_from_slice(&item.unwrap());
    }

    log::debug!("bytes: {:?}", bytes);
    log::debug!("bytes length: {:?}", bytes.len());

    let pdf_text = match pdf_extract::extract_text_from_mem(&bytes) {
        Ok(text) => text,
        Err(e) => { // PDF parsing error only with Axios
            log::error!("Error: {:#?}", e);
            return HttpResponse::BadRequest().json(ErrorResponse::new("error parsing pdf".to_string(), e.to_string()));
        }
    };
...

核心问题

用Postman或cURL直接调用Rust路由完全正常,参考命令:

# This works
curl -X POST -H "Content-Type: application/pdf" -H "Authorization: Bearer <TOKEN>" --data-binary "@/path/to/file.pdf" http://localhost:8080/path/to/api

但通过Axios转发请求时,PDF解析库提示解析PDF Trailer出错。对比字节数发现:Axios转发的请求约101k字节,而Postman/cURL的请求是58k字节,推测字节数异常是问题根源。尝试过用FormData也没解决,希望能调整Actix路由实现兼容,目前只知道用Payload提取器读取PDF的方式。


解决方案

方案1:修复Next API中请求体的处理方式

Next.js的API路由默认会自动解析请求体,导致原始PDF二进制数据被转成字符串或其他格式,转发给Axios时数据损坏。需要禁用自动解析,直接读取原始Buffer:

// 禁用Next的自动解析配置
export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function handler(req, res) {
  const { token } = req.session.user;
  const api_url = `${process.env.SERVER_API_URL}/path/to/api` as string;

  // 读取原始二进制数据
  const chunks = [];
  for await (const chunk of req) {
    chunks.push(chunk);
  }
  const body = Buffer.concat(chunks);

  try {
    const response = await axios.post(api_url, body, {
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/pdf",
      },
    });
    res.json({ ...response.data, isLoggedIn: true });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
}

方案2:调整Axios的请求配置

确保Axios发送原始二进制数据,避免自动序列化,添加transformRequest配置阻止请求体转换:

const response = await axios.post(api_url, body, {
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/pdf",
  },
  transformRequest: [(data) => data], // 阻止Axios修改请求体
});

方案3:Actix端兼容处理(无法修改前端/Next API时)

如果只能从Actix端调整,可尝试检查请求体是否被编码(如base64)并解码:

pub async fn route_function(db: Data<DatabaseRepository>, mut payload: Payload, auth: AuthorizationService) -> HttpResponse {
    let id = auth.id;
    let mut bytes = BytesMut::new();
    while let Some(item) = payload.next().await {
        bytes.extend_from_slice(&item.unwrap());
    }

    log::debug!("bytes length: {:?}", bytes.len());

    // 尝试解码base64(字节数膨胀符合base64编码特征)
    let pdf_bytes = match base64::decode(&bytes) {
        Ok(decoded) => {
            log::debug!("Decoded base64 to bytes length: {}", decoded.len());
            decoded
        },
        Err(_) => bytes.to_vec(), // 非base64则用原始字节
    };

    let pdf_text = match pdf_extract::extract_text_from_mem(&pdf_bytes) {
        Ok(text) => text,
        Err(e) => {
            log::error!("Error: {:#?}", e);
            return HttpResponse::BadRequest().json(ErrorResponse::new("error parsing pdf".to_string(), e.to_string()));
        }
    };
    // 后续业务逻辑...
}

说明

字节数从58k膨胀到101k,大概率是Next自动将二进制转成UTF-8字符串导致的,方案1是最根本的解决方式——确保请求体在转发过程中保持原始二进制格式,未被任何解析或转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:05:02