一.前端上传图片的方式
- 表单提交方式
- HTML5方式(base64、blob)
表单提交方式
<!DOCTYPE html><html><body><h2>HTML Forms</h2><form action="/file" method="POST" enctype="multipart/form-data"><label for="fname">First name:</label><br /><input type="text" id="fname" name="fname" value="张" /><br /><label for="lname">Last name:</label><br /><input type="text" id="lname" name="lname" value="三" /><br /><br /><label for="file">file:</label><br /><input type="file" id="file" name="file" /><br /><br /><input type="submit" value="Submit" /></form></body></html>
这里简单写了一个表单提交的html代码,这里需要注意的是,如果不指定enctype=”multipart/form-data”,他默认会以 application/x-www-form-urlencoded这种编码方式进行网络请求,form-data格式请求会用一个boundary分隔符区分。在表单传输中如果不指定form-data格式会无法传输文件。这个也比较好理解,因为如果用fname=xxx&file=xxx这种格式传输会有几个问题,1.文件名等信息需要单独和服务端定一套新的上传规范。2.文件传输很大,拼在file后面有很大不确定性。
表单提交对应的服务端程序(express示例)
const fileUpload = require('express-fileupload')app.post("/file",fileUpload(),(req, res) => {console.log(req.files, req.body)req.files.file.mv(path.resolve(__dirname, 'upload/a.jpg'))res.send("ok")})
HTML5方式
1.base64
<!DOCTYPE html><html><body><h2>HTML Forms</h2><div><label for="file">file:</label><br><input type="file" id="file" name="file"><br><br><input onClick='submit()' type="submit" value="Submit"></div><script>let upload = {}function submit(){console.log('here', upload)fetch('/submitb64', {method : "POST",//body : `name=${upload.name}&data=${upload.data}`,body : JSON.stringify(upload),headers : {//'Content-Type' : 'application/x-www-form-urlencoded''Content-Type' : 'application/json'}})}document.getElementById("file").addEventListener('change', e=>{const files = e.target.filesfor(let file of files) {const fr = new FileReader()fr.readAsDataURL(file)fr.onload = () => {console.log(fr.result)upload.data = fr.result.substr(22)upload.name = file.name}}})</script></body></html>
如果使用base64的方式来传输文件,需要利用FileReader来对file类型进行转换。读取base64后前端做了一个substr字符串删除,来删除前缀的base64描述,也就是data:image/png;base64, 这个部分。之后就是真正的base64编码了。转换之后传输我们需要选择一个合适的传输方式,在上述代码中有注释一个片段,是用x-www-form-urlencoded方式传输,这是很多开发者可能会下意识想到的方法,至于为什么不能用这种方式上面已经讲过。通常来说我们会选择json的方式来进行传输base64文件。
html5base64对应的服务端程序(express示例)
const bodyParser = require('body-parser')app.post("/submitb64",bodyParser.json(),(req, res) => {const buffer = new Buffer(req.body.data, 'base64')console.log(req.body.data.length)fs.writeFileSync(path.resolve(__dirname, "upload/x.jpg"),buffer)res.send("ok")})
2.blob
众所周知,base64编码会将文件体积变大,因此在传输一些较大的文件时不建议使用这种方式来传输。因此html5中还可以利用blob的方法来传输。
<!DOCTYPE html><html><body><h2>HTML Forms</h2><div><label for="file">file:</label><br><input type="file" id="file" name="file"><br><br><input onClick='submit()' type="submit" value="Submit"></div><script>let upload = {}function submit(){console.log('here', upload)const formData = new FormData()formData.append('name', upload.name)formData.append('file', upload.data)fetch('/submitbinary', {method : "POST",body : formData,headers : {// 这里如果设置了Content-Type会有Bug// 'Content-Type' : 'multipart/form-data'}})}document.getElementById("file").addEventListener('change', e=>{const files = e.target.filesfor(let file of files) {upload.data = fileupload.name = file.name}})</script></body></html>
这里注意有个大坑,fetch请求中不要加’Content-Type’ : ‘multipart/form-data’这个header,如果加了这个header会导致请求中content-type中后面没有boundary,导致服务端无法解析。fetch在发送请求中如果发现body中是form-data的时候,会自己加上这个编码格式的header并且自动加上boundary。
html5 blob对应的服务端程序(express示例)
app.post("/submitbinary",fileUpload(),(req, res) => {console.log(req.files, req.body)req.files.file.mv(path.resolve(__dirname, 'upload/b.jpg'))res.send("ok")})
该方法的优点:1.传输比base64更快。2.对cpu压力更小。 因此没有特殊原因的情况下通常用blob上传。
