使用fetch() POST上传PDF报415 Unsupported Media Type错误求助
使用fetch()上传PDF至HubSpot API遇415/400错误的解决办法
问题情况
用fetch()上传PDF到HubSpot API时,一直碰到415 Unsupported Media Type错误。PDF和JS文件在同一目录,文件名没问题。试了各种Content-Type设置:
- 设为
"multipart/form-data"返回400错误; - 设为
"application/json"或"text/plain"返回415错误; - 删掉Content-Type头还是返回400错误。
用request.post()能成功上传,但想换成fetch()实现,当前代码如下:
async function uploadFile(filePath, extension, timestamp) { const url = "https://api.hubapi.com/files/v3/files"; // const url = "https://api.hubapi.com/filemanager/api/v3/files/upload"; // also doesn't work. var filename = `${filePath}.${extension}`; var fileOptions = { access: 'PRIVATE', overwrite: false, duplicateValidationStrategy: 'NONE', duplicateValidationScope: 'ENTIRE_PORTAL' }; var formData = { file: fs.createReadStream(filename), fileName: `${filename} (${timestamp}).${extension}`, options: JSON.stringify(fileOptions), folderPath: 'Quotations' }; try { const response = await fetch(url, { "method": "POST", "formData": formData, "headers": { 'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`, "Content-Type": "application/pdf" } }); if(!response.ok) { throw new Error(`Error. Response not ok: ${response.status}`); } const data = await response.json(); return data; } catch(error) { console.log(`Error: ${error}`); } } const fileId = uploadFile("Quotation", "pdf", getCurrentTimestamp()); fileId.then((data) => console.log(data));
问题原因
- Node.js环境下的
fetch(不管是原生还是node-fetch)不支持直接传普通对象当formData,必须用标准FormData构造请求体; - 手动设置
Content-Type: application/pdf会覆盖multipart/form-data的正确请求头,导致HubSpot API无法解析请求结构; - 文件流的传递方式不对,没有正确告知API文件的类型和名称。
修改后的代码
先确保安装依赖:
npm install form-data node-fetch
修改后的上传函数:
const fetch = require('node-fetch'); const FormData = require('form-data'); const fs = require('fs'); async function uploadFile(filePath, extension, timestamp) { const url = "https://api.hubapi.com/files/v3/files"; const filename = `${filePath}.${extension}`; const newFileName = `${filename} (${timestamp}).${extension}`; const fileOptions = { access: 'PRIVATE', overwrite: false, duplicateValidationStrategy: 'NONE', duplicateValidationScope: 'ENTIRE_PORTAL' }; // 构造标准FormData实例 const formData = new FormData(); // 附加文件流,指定文件名和PDF类型 formData.append('file', fs.createReadStream(filename), { filename: newFileName, contentType: 'application/pdf' }); formData.append('fileName', newFileName); formData.append('options', JSON.stringify(fileOptions)); formData.append('folderPath', 'Quotations'); try { const response = await fetch(url, { method: "POST", body: formData, // 用body传递FormData,不是自定义的formData字段 headers: { 'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`, // 用FormData自动生成的请求头,包含正确的boundary ...formData.getHeaders() } }); if (!response.ok) { // 获取API返回的错误详情,方便排查 const errorInfo = await response.text(); throw new Error(`请求失败: ${response.status} - ${errorInfo}`); } const data = await response.json(); return data; } catch(error) { console.error(`错误: ${error.message}`); } } // 补充时间戳函数示例 function getCurrentTimestamp() { return new Date().toISOString().replace(/[:.]/g, '-'); } const uploadPromise = uploadFile("Quotation", "pdf", getCurrentTimestamp()); uploadPromise.then((data) => console.log(data)).catch(err => console.error(err));
关键修改点
- 用
form-data库创建标准的FormData对象,这是Node.js下fetch处理文件上传的正确方式; - 附加文件时指定文件名和
application/pdf类型,让HubSpot能识别文件格式; - 请求体用
body: formData传递,原代码的formData字段是错误的; - 不要手动设置
Content-Type,formData.getHeaders()会自动生成包含boundary的multipart/form-data头,这是解决400/415错误的核心; - 捕获错误时获取响应文本,能看到API返回的具体错误信息,方便调试。
内容的提问来源于stack exchange,提问作者improbablyconfused
相关产品推荐
相关产品推荐

