问题描述
我正在尝试通过 imgur 的 API 实现 apollo-datasource-rest
来处理通过 URL 上传的图片(文档在这里:https://apidocs.imgur.com/)
我最初收到一个 400
错误,它读取 We don't support that file type!
,并确定这是由于 apollo-datasource-rest
自动将 Content-Type
设置为 application/json
。使用 form-data
npm 包修复该问题后,我的代码如下所示:
class imgurAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = "https://api.imgur.com/3/";
}
willSendRequest(request) {
request.headers.set("Content-Type","multipart/form-data");
request.headers.set(
"Authorization",`Client-ID ${process.env.imgur_CLIENT_ID}`
);
console.log(request);
}
async uploadImageFromUrl(url) {
const formData = new FormData();
formData.append("image",url);
return this.post("upload",formData);
}
}
我现在不再收到 We don't support that file type!
错误,但我仍然收到 400
响应,状态文本仅为 Bad Request
。上一代码片段中的 console.log()
打印:
{
method: 'POST',path: 'upload',body: FormData {
_overheadLength: 104,_valueLength: 80,_valuesToMeasure: [],writable: false,readable: true,dataSize: 0,maxDataSize: 2097152,pauseStreams: true,_released: false,_streams: [
'----------------------------594660553626244976225816\r\n' +
'Content-disposition: form-data; name="image"\r\n' +
'\r\n','https://upload.wikimedia.org/wikipedia/commons/a/a0/Sunflower_as_gif_websafe.gif',[Function: bound ]
],_currentStream: null,_insideLoop: false,_pendingNext: false,_boundary: '--------------------------594660553626244976225816'
},params: URLSearchParams {},headers: Headers {
[Symbol(map)]: [Object: null prototype] {
'Content-Type': [Array],Authorization: [Array]
}
}
}
我在这里错过了什么? API 似乎正在接受我的表单数据,所以我认为其他标题之一可能存在一些问题,但在 Postman 中看起来只有几个必需的标题,其中大部分是计算出来的(例如 Content-Length
),所以我假设 apollo-datasource-rest
必须处理这个。
解决方法
对 multipart/form-data
进行了更多研究后,我发现 boundary
参数是必需的,必须将其添加到请求中的 Content-Type
值中才能使服务器能够解析有效载荷。此外,我无法将其手动设置为请求中的参数(至少不是以实际工作的方式)。 Postman 通常会在发送请求时计算此字段,但 apollo-datasource-rest
不会自动处理。
将 Content-Type
更改为 application/x-www-form-urlencoded
并使用 url 编码字符串代替 form-data
解决了该问题。
这是更新后的代码:
willSendRequest(request) {
request.headers.set("Content-Type",`application/x-www-form-urlencoded`);
request.headers.set(
"Authorization",`Client-ID ${process.env.IMGUR_CLIENT_ID}`
);
console.log(request);
}
async uploadImageFromUrl(url) {
const formData = `image=${url}&album=${process.env.IMGUR_ALBUM_DELETE_HASH}&type=url`;
return this.post("upload",formData);
}