一.前端上传图片的方式

  • 表单提交方式
  • HTML5方式(base64、blob)

表单提交方式

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. <h2>HTML Forms</h2>
  5. <form action="/file" method="POST" enctype="multipart/form-data">
  6. <label for="fname">First name:</label><br />
  7. <input type="text" id="fname" name="fname" value="张" /><br />
  8. <label for="lname">Last name:</label><br />
  9. <input type="text" id="lname" name="lname" value="三" /><br /><br />
  10. <label for="file">file:</label><br />
  11. <input type="file" id="file" name="file" /><br /><br />
  12. <input type="submit" value="Submit" />
  13. </form>
  14. </body>
  15. </html>

这里简单写了一个表单提交的html代码,这里需要注意的是,如果不指定enctype=”multipart/form-data”,他默认会以 application/x-www-form-urlencoded这种编码方式进行网络请求,form-data格式请求会用一个boundary分隔符区分。在表单传输中如果不指定form-data格式会无法传输文件。这个也比较好理解,因为如果用fname=xxx&file=xxx这种格式传输会有几个问题,1.文件名等信息需要单独和服务端定一套新的上传规范。2.文件传输很大,拼在file后面有很大不确定性。

表单提交对应的服务端程序(express示例)

  1. const fileUpload = require('express-fileupload')
  2. app.post(
  3. "/file",
  4. fileUpload(),
  5. (req, res) => {
  6. console.log(req.files, req.body)
  7. req.files.file.mv(path.resolve(__dirname, 'upload/a.jpg'))
  8. res.send("ok")
  9. }
  10. )

HTML5方式

1.base64

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. <h2>HTML Forms</h2>
  5. <div>
  6. <label for="file">file:</label><br>
  7. <input type="file" id="file" name="file"><br><br>
  8. <input onClick='submit()' type="submit" value="Submit">
  9. </div>
  10. <script>
  11. let upload = {}
  12. function submit(){
  13. console.log('here', upload)
  14. fetch('/submitb64', {
  15. method : "POST",
  16. //body : `name=${upload.name}&data=${upload.data}`,
  17. body : JSON.stringify(upload),
  18. headers : {
  19. //'Content-Type' : 'application/x-www-form-urlencoded'
  20. 'Content-Type' : 'application/json'
  21. }
  22. })
  23. }
  24. document.getElementById("file").addEventListener('change', e=>{
  25. const files = e.target.files
  26. for(let file of files) {
  27. const fr = new FileReader()
  28. fr.readAsDataURL(file)
  29. fr.onload = () => {
  30. console.log(fr.result)
  31. upload.data = fr.result.substr(22)
  32. upload.name = file.name
  33. }
  34. }
  35. })
  36. </script>
  37. </body>
  38. </html>

如果使用base64的方式来传输文件,需要利用FileReader来对file类型进行转换。读取base64后前端做了一个substr字符串删除,来删除前缀的base64描述,也就是data:image/png;base64, 这个部分。之后就是真正的base64编码了。转换之后传输我们需要选择一个合适的传输方式,在上述代码中有注释一个片段,是用x-www-form-urlencoded方式传输,这是很多开发者可能会下意识想到的方法,至于为什么不能用这种方式上面已经讲过。通常来说我们会选择json的方式来进行传输base64文件。

html5base64对应的服务端程序(express示例)

  1. const bodyParser = require('body-parser')
  2. app.post(
  3. "/submitb64",
  4. bodyParser.json(),
  5. (req, res) => {
  6. const buffer = new Buffer(req.body.data, 'base64')
  7. console.log(req.body.data.length)
  8. fs.writeFileSync(
  9. path.resolve(__dirname, "upload/x.jpg"),
  10. buffer)
  11. res.send("ok")
  12. }
  13. )

2.blob

众所周知,base64编码会将文件体积变大,因此在传输一些较大的文件时不建议使用这种方式来传输。因此html5中还可以利用blob的方法来传输。

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. <h2>HTML Forms</h2>
  5. <div>
  6. <label for="file">file:</label><br>
  7. <input type="file" id="file" name="file"><br><br>
  8. <input onClick='submit()' type="submit" value="Submit">
  9. </div>
  10. <script>
  11. let upload = {}
  12. function submit(){
  13. console.log('here', upload)
  14. const formData = new FormData()
  15. formData.append('name', upload.name)
  16. formData.append('file', upload.data)
  17. fetch('/submitbinary', {
  18. method : "POST",
  19. body : formData,
  20. headers : {
  21. // 这里如果设置了Content-Type会有Bug
  22. // 'Content-Type' : 'multipart/form-data'
  23. }
  24. })
  25. }
  26. document.getElementById("file").addEventListener('change', e=>{
  27. const files = e.target.files
  28. for(let file of files) {
  29. upload.data = file
  30. upload.name = file.name
  31. }
  32. })
  33. </script>
  34. </body>
  35. </html>

这里注意有个大坑,fetch请求中不要加’Content-Type’ : ‘multipart/form-data’这个header,如果加了这个header会导致请求中content-type中后面没有boundary,导致服务端无法解析。fetch在发送请求中如果发现body中是form-data的时候,会自己加上这个编码格式的header并且自动加上boundary。

html5 blob对应的服务端程序(express示例)

  1. app.post(
  2. "/submitbinary",
  3. fileUpload(),
  4. (req, res) => {
  5. console.log(req.files, req.body)
  6. req.files.file.mv(path.resolve(__dirname, 'upload/b.jpg'))
  7. res.send("ok")
  8. }
  9. )

该方法的优点:1.传输比base64更快。2.对cpu压力更小。 因此没有特殊原因的情况下通常用blob上传。