Apollo REST 数据源和 Imgur API - 使用表单数据不断收到 400 个错误请求

问题描述

我正在尝试通过 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);
  }