likes
comments
collection
share

在 Node.js 中使用 FormData 传输表单文件

作者站长头像
站长
· 阅读数 12

在浏览器中,我们用 <form> 元素来提交表单中的文件,表单的编码类型由 enctype 属性决定,必须是以下三种之一:

  • application/x-www-form-urlencoded:表单默认的编码类型
  • multipart/form-data:如果包含文件,只能选择这种类型
  • text/plain:无需编码,直接发送
var form = new FormData()
form.append('my_string', 'my value')
form.append('my_integer', 1)
form.append('my_boolean', true)
form.append('my_buffer', Buffer.from('hello'))
form.append('my_file', fs.readFileSync('/foo/bar.jpg'))
form.append('my_file', fs.createReadStream('/foo/bar.jpg'))

用法很简单,不再赘述,对于文件类型,用 createReadStream 或者 readFileSync 两种方式来读取即可,这里主要强调一点:form-data 对这两种格式的处理稍有不同。请看下面两段代码:

  1. createReadStream

    var media = new FormData()
    media.append('contentType', 'image/jpeg')
    media.append('value', fs.createReadStream('/Users/keliq/Pictures/1.jpeg'))
    
  2. readFileSync

    var media = new FormData()
    media.append('contentType', 'image/jpeg')
    media.append('value', fs.readFileSync('/Users/keliq/Pictures/1.jpeg'))
    

抓包得到的结果是:

  1. createReadStream

    ----------------------------015517802272525417891317
    Content-Disposition: form-data; name="contentType"
    
    image/jpeg
    ----------------------------015517802272525417891317
    Content-Disposition: form-data; name="value"; filename="1.jpeg"
    Content-Type: image/jpeg
    
  2. readFileSync

    ----------------------------152374567568773937407488
    Content-Disposition: form-data; name="contentType"
    
    image/jpeg
    ----------------------------152374567568773937407488
    Content-Disposition: form-data; name="value"
    Content-Type: application/octet-stream
    

最后发现原因在这个 merge 里面,把 Content-Type 默认设置为 application/octet-stream 了,那如果想和 createReadStream 的格式一样,需要改成这样子:

var media = new FormData()
media.append('contentType', 'image/jpeg')
media.append('value', fs.readFileSync('/Users/keliq/Pictures/1.jpeg'), '1.jpeg')

这是 form-data 库提供的 API:

// Set filename by providing a string for options
form.append( 'my_file', fs.createReadStream('/foo/bar.jpg'), 'bar.jpg' );

// provide an object.
form.append( 'my_file', fs.createReadStream('/foo/bar.jpg'), {filename: 'bar.jpg', contentType: 'image/jpeg', knownLength: 19806} );

查看了一下源码,原因是如果提供了文件名,就会用 mime-types 的 lookup 方法自动判断 Content-Type,例如:

mime.lookup('json') // 'application/json'
mime.lookup('.md') // 'text/markdown'
mime.lookup('file.html') // 'text/html'
mime.lookup('folder/file.js') // 'application/javascript'

这也是为什么当提供了 1.jpeg 参数之后,Content-Type 会从默认的 application/octet-stream 变成了 image/jpeg

转载自:https://juejin.cn/post/6947700062461886477
评论
请登录