从公众号上传临时素材的接口到 axios 计算 content-length

如果你像我一样,在 node 中应用 axios 实例调用公众号上传临时素材的接口,很有可能会出现客户端错误。公众号该接口需要 post/form 的方式来上传,在 curl 中加上参数 -F media=@test-case-1.mp3 可以测得接口调用成功。所以问题就出在代码中,有一些参数是不对的。

文档中有介绍,media 字段所表征的 formdata 是包含有 filename, filelength, content-type等信息,在 node 中,FormData 可以由 form-data 库提供。但是字段还是不全,缺失的那个字段叫做 content-length

content-length 请求头提交给微信公众号接口,现在可以成功调通。该 content-length 由 formdata 可以计算得出。

代码如下:

async function uploadMedia({ filePath, type }) {
  const { access_token: accessToken, expires_in: expiresIn } =
    await getAccessToken();

  // let url = `https://api.weixin.qq.com/cgi-bin/media/upload?access_token=${accessToken}&type=${type}`;
  // debuglog(url);
  const form = new FormData();
  form.append('media', fs.createReadStream(filePath));

  let contentLen = await promisify(form.getLength).call(form);
  debuglog(`[contentLen](${contentLen})`);
  const headers = form.getHeaders({ 'content-length': contentLen });

  let res = await axios.request({
    method: 'POST',
    url: '/media/upload',
    params: { access_token: accessToken, type },
    data: form,
    // 这里 content-length 一定要设置, axios 漏掉了,所以利用 formData 来补偿
    headers,
  });

  return res.data;
}

关键的代码 form.getLength((err, len) => {}), 利用其来计算 contentLength

调用

test.skip('1 voice', async () => {
  let filePath = path.join(process.cwd(), 'test/secret/test-case-1.mp3');
  debuglog(filePath);

  let r = await uploadMedia({ filePath, type: 'voice' });
  console.log(r);
});

只需要调用 uploadMedia, 参数 filePath, type 两个。

关于本文如您有任何想法和意见,欢迎与我们联系,邮箱地址zhi@uqugu.com
您对本文有什么看法,喜欢或者不喜欢都可以发表意见。