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

NextJS 13 App目录下PDF上传API无法正常工作

PDF转Word应用:客户端调用正常,迁移至Next.js API路由后报错

我开发了一个PDF转Word的小型应用,直接在客户端组件调用外部API时完全正常,但把上传逻辑迁移到app/api/process/route.js的API路由后,接口持续返回错误。


客户端可运行代码

"use client";

import { useState } from "react";

export default function PDFToDocConverter() {
  const [selectedFile, setSelectedFile] = useState(null);
  const [downloadLink, setDownloadLink] = useState(null);
  const [loading, setLoading] = useState(false);

  const handleFileChange = (event) => {
    setSelectedFile(event.target.files[0]);
  };

  const handleUpload = async () => {
    setLoading(true);
    const myHeaders = new Headers();
    myHeaders.append("Apikey", "my API key");

    const formdata = new FormData();
    formdata.append("inputFile", selectedFile);

    const requestOptions = {
      method: "POST",
      headers: myHeaders,
      body: formdata,
      redirect: "follow",
    };

    fetch("https...", requestOptions)
      .then((response) => response.blob())
      .then((blob) => {
        const blobUrl = URL.createObjectURL(blob);
        setDownloadLink(blobUrl);
        setLoading(false);
      })
      .catch((error) => {
        console.error("Error:", error);
        setLoading(false);
      });
  };

  return (
    <div>
      <h1>PDF to DOC Converter</h1>

      <div>
        <input type="file" name="inputFile" onChange={handleFileChange} />
        <button onClick={handleUpload}>Upload File</button>
      </div>

      {loading ? (
        <p>Loading...</p>
      ) : downloadLink ? (
        <div>
          <a href={downloadLink} download="converted.docx">
            <button>Download Converted File</button>
          </a>
        </div>
      ) : null}
    </div>
  );
}

出错的API路由代码(app/api/process/route.js)

import { NextResponse } from "next/server";

export async function POST(req) {
  const formData = await req.formData();
  const file = formData.get("inputFile");

  console.log(file, "file");

  if (!file) {
    return NextResponse.json({ success: false });
  }

  const myHeaders = new Headers();
  myHeaders.append("Apikey", "my_api_key");

  const formdata = new FormData();
  formdata.append("inputFile", file, file.name);
  console.log(file, "fileee");

  const requestOptions = {
    method: "POST",
    headers: myHeaders,
    body: formdata,
    redirect: "follow",
  };

  const response = await fetch("https....", requestOptions);

  console.log(response, "responseeeee");

  if (response.statusText === "OK") {
    const responseText = await response.text();
    return NextResponse.json({ success: true, responseData: responseText });
  } else {
    return NextResponse.json({
      success: false,
      error: "An error occurred during conversion.",
    });
  }
}

问题分析与修复方案

核心问题

  1. 响应处理错误:外部API返回的是二进制Word文档,原API路由用response.text()解析会损坏文件内容,且用statusText === "OK"判断请求成功的逻辑不可靠(状态文本可能因API不同而变化)。
  2. 响应格式错误:直接返回JSON无法传递二进制文件给客户端,需要原样返回二进制数据流。

修复后的API路由代码

import { NextResponse } from "next/server";

export async function POST(req) {
  const formData = await req.formData();
  const file = formData.get("inputFile");

  if (!file) {
    return NextResponse.json(
      { success: false, error: "未上传文件" },
      { status: 400 }
    );
  }

  const myHeaders = new Headers();
  myHeaders.append("Apikey", "my_api_key");

  const externalFormData = new FormData();
  externalFormData.append("inputFile", file, file.name);

  const requestOptions = {
    method: "POST",
    headers: myHeaders,
    body: externalFormData,
    redirect: "follow",
  };

  try {
    const response = await fetch("https....", requestOptions);

    if (!response.ok) {
      throw new Error(`外部API请求失败:${response.status}`);
    }

    // 获取二进制blob并直接返回给客户端
    const blob = await response.blob();
    return new NextResponse(blob, {
      headers: {
        "Content-Type": blob.type,
        "Content-Disposition": 'attachment; filename="converted.docx"',
      },
    });
  } catch (error) {
    console.error("转换错误:", error);
    return NextResponse.json(
      { success: false, error: error.message },
      { status: 500 }
    );
  }
}

对应客户端代码修改(调用内部API)

需要将客户端的handleUpload改为调用内部API,同时移除客户端的密钥暴露:

const handleUpload = async () => {
  setLoading(true);
  try {
    const formData = new FormData();
    formData.append("inputFile", selectedFile);

    const response = await fetch("/api/process", {
      method: "POST",
      body: formData,
    });

    if (!response.ok) {
      throw new Error("转换失败");
    }

    const blob = await response.blob();
    const blobUrl = URL.createObjectURL(blob);
    setDownloadLink(blobUrl);
  } catch (error) {
    console.error("错误:", error);
  } finally {
    setLoading(false);
  }
};

额外注意事项

  • 确保外部API的URL配置正确
  • 迁移到API路由的核心意义之一是避免在客户端暴露API密钥,原客户端代码存在密钥泄露风险
  • 可在API路由中添加更详细的日志,方便后续排查问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:03:17