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.", }); } }
问题分析与修复方案
核心问题
- 响应处理错误:外部API返回的是二进制Word文档,原API路由用
response.text()解析会损坏文件内容,且用statusText === "OK"判断请求成功的逻辑不可靠(状态文本可能因API不同而变化)。 - 响应格式错误:直接返回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
相关产品推荐
相关产品推荐

