收藏
回答

公众号开发 fetch 调用【上传图文消息内的图片获取URL】接口时,返回 412 错误?

我用的 NodeJS 开发的,在用 node-fetch 上传图片是返回的 HTTP STATUS 是 412 错误,我很确定我的代码是正确的,并且发现了有类似相同的问题

这是另一个问题的链接 https://developers.weixin.qq.com/community/develop/doc/00000ef32dc64883d9d93f31f56800

但我对此问题的回答并不满意,因为 request 库早在很多年前就弃用了,原作者推荐用 node-fetch

我觉得不应该用弃用的库应对目前业务,可无奈所搜了一堆现有的微信公众号开发的列子,用的都是 request

希望社区有大神给予解答,附上我的代码

const fetch = require('node-fetch')
const fs = require('fs')
const FormData = require('form-data')

const media = fs.createReadStream('foo.jpg')
const formData = new FormData()
formData.append('media', media)
const response = await fetch(url, {
      method: 'POST',
      body: formData
    })

if (!response.ok) {
      console.log(response.status)
      reject('error')
      throw new Error('Upload material failed')
    }

// 412
// Error: Upload material failed


最后一次编辑于  2022-10-23
回答关注问题邀请回答
收藏

1 个回答

  • Leeco
    Leeco
    2022-10-23

    好吧,既然没人回答,我自己折腾了一下午解决了问题。

    这里面坑真多,为了能抓 node server 包就花了我好长时间。

    我前后抓了 request 和 node-fetch 的包,进行报文头部的分析,因为我猜测,肯定是报文某个字段请求微信服务器它不认可。

    request post

    host: api.weixin.qq.com
    content-type: multipart/form-data; boundary=--------------------------432155727223273682777525
    content-length: 45303
    Connection: close
    
    ----------------------------432155727223273682777525
    Content-Disposition: form-data; name="media"; filename="2.jpg"
    Content-Type: image/jpeg
    
    ...DATA...
    
    ----------------------------432155727223273682777525--
    


    node-fetch post

    Host: api.weixin.qq.com
    Content-Type: multipart/form-data;boundary=--------------------------297137759555768400521474
    Accept: */*
    User-Agent: node-fetch/1.0 (+https://github.com/bitinn/node-fetch)
    Accept-Encoding: gzip,deflate
    Connection: close
    Transfer-Encoding: chunked
    
    ----------------------------297137759555768400521474
    Content-Disposition: form-data; name="media"; filename="2.jpg"
    Content-Type: image/jpeg
    
    ...DATA...
    
    ----------------------------297137759555768400521474--
    


    前后对面他们的请求报文字段几乎一致,不一致的 Accept User-Agent Accept-Encoding Transfer-Encoding,这几个都是无关紧要的,一般来说服务器不会对他们做出逻辑回应。

    那么问题应该就出在 node-fetch 没有自动设置 content-length 了,猜测微信服务器应该对这个字段做了判断校验,比如媒体文件大小限制,发现没法判断,则返回了错误。

    问题找到了,那就容易解决了(虽然也不容易还是有何种坑)

    为什么 node-fetch 不会自动设置 content-length 字段呢,不应该啊,于是我扒了下官方文档看到这个

    我就是以流文件上传的,所以他没法设置这个字段,那我就自己设置他好了

    上代码

    const fetch = require('node-fetch')
    const fs = require('fs')
    const FormData = require('form-data')
    
    const media = fs.createReadStream('foo.jpg')
    // 获取文件的信息
    const stats = fs.statSync('foo.jpg')
    const formData = new FormData()
    // 在这里传递文件的长度
    formData.append('media', media, { knownLength: stats.size })
    const response = await fetch(url, {
          method: 'POST',
          headers:{
             // 千万不要在这里传 'Content-Length',因为实际上你的报文长度和文件大小并不一致,之前我设置了 formData 的大小,这里就能自动生成真实报文长度了
          }
          body: formData
        })
    
    if (!response.ok) {
          console.log(response.status)
          reject('error')
          throw new Error('Upload material failed')
     }else{
          console.log(await response.json())
     }
            
            
            
    


    2022-10-23
    有用 3
    回复
登录 后发表内容