在 Node.js 中使用 FormData 传输表单文件
在浏览器中,我们用 <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 对这两种格式的处理稍有不同。请看下面两段代码:
-
createReadStream
var media = new FormData() media.append('contentType', 'image/jpeg') media.append('value', fs.createReadStream('/Users/keliq/Pictures/1.jpeg'))
-
readFileSync
var media = new FormData() media.append('contentType', 'image/jpeg') media.append('value', fs.readFileSync('/Users/keliq/Pictures/1.jpeg'))
抓包得到的结果是:
-
createReadStream
----------------------------015517802272525417891317 Content-Disposition: form-data; name="contentType" image/jpeg ----------------------------015517802272525417891317 Content-Disposition: form-data; name="value"; filename="1.jpeg" Content-Type: image/jpeg
-
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