一、文章参考

  1. FormData API 参考

二、前台 axios 上传

  1. form表单提交,method 使用post方式
  2. 表单一定要设置enctype="multipart/form-data"

2.1 FormData 介绍

FormData 接口提供了一种表示表单数据的键值对的构造方式,经过它的数据可以使用 XMLHttpRequest.send() 方法送出,本接口和此方法都相当简单直接。如果送出时的编码类型被设为 “multipart/form-data”,它会使用和表单一样的格式。

FormData API 参考

2.2 axios.post()上传文件步骤

构造form’Data,使用axios上传文件
在项目中使用axios上传文件,记得new一个纯净的axios或者考虑用ajax请求。因为axios在项目估计已经用了全局配置请求头等信息,这里的配置可能被全局请求头拦截,导致请求失败。

let param = new FormData();
param.append("name", "wiiiiiinney");
//通过append向form对象添加数据
param.append("file", file);
//FormData私有类对象,访问不到,可以通过get判断值是否传进去
console.log(param.get("file"));

let config = {
	//添加请求头
	headers: { "Content-Type": "multipart/form-data" },
	//添加上传进度监听事件
	onUploadProgress: e => {
		var completeProgress = ((e.loaded / e.total * 100) | 0) + "%";
		this.progress = completeProgress;
	}
};

axios.post('http://127.0.0.1:8778/upload', param, config)
.then(
	function (response) { console.log(response); 
})
.catch(function (error) {
	console.log(error);
});

2.3 axios 实例 上传文件

在这里插入图片描述

<template>
  <section class="text_messaging">
    <span class="breadcrumbBtnGroup">
      <el-button type="link" @click="importClick">导入</el-button>
      <!-- 不显示 文件上传的图标 -->
      <input ref="inputfile" type="file" style="visibility:hidden" @change="riverConfigImport"/>
    </span>
  </section>
</template>

<script>
import * as API from '@/api/index.js'
export default {
  methods: {
    importClick () {
      this.$refs.inputfile.click()
    },
    // 导入河段配置
    riverConfigImport (event) {
      console.log(arguments)
      debugger
      const file = event.target.files[0]
      let param = new FormData();
      //通过append向form对象添加数据
      param.append('file', file);
      //FormData私有类对象,访问不到,可以通过get判断值是否传进去
      console.log(param.get('file'));
      let config = {
        //添加请求头
        headers: { 'Content-Type': 'multipart/form-data' },
      };
      API.riverConfigImportService(param, config).then(res=> {
        if (res.msg === 'success') {
          this.$message({
            message: '上传成功!',
            type: 'success'
          })
        }
      })
    }
  }
}
</script>

API 配置文件index.js

const http = axios.create({
  timeout: 20000,
  withCredentials: true,
  headers: { 'X-Requested-With': 'XMLHttpRequest' },
})

// 相应拦截器
http.interceptors.response.use(
  function (response) {
  // 判断请求是否是二进制
    if (response.headers && response.headers['content-type'] && response.headers['content-type'].indexOf('octet-stream') > 0) {
      return response
    }

    // 请求多语言的json文件
    if (/.*\.json$/.test(response.config.url)) {
      return response
    }

    // 根据响应数据判断是否登录过期
    if (response.data.errorCode === REFRESH_BY_HEADER) {
      let refreshUrl = response.headers['refresh-url'].split('?')[0]
      refreshUrl =
        refreshUrl +
        '?service=' +
        location.protocol +
        '//' +
        location.host +
        location.pathname +
        encodeURIComponent(location.search)
      location.href = refreshUrl
      return
    }

    // 对错误进行统一处理
    if (response.data.code !== REQUEST_SUCCESS) {
      if (!response.config.noMsg && response.data.msg) {
        Message.error(i18n.t(response.data.msg))
      }
      return Promise.reject(response)
    } else if (response.data.code === REQUEST_SUCCESS && response.config.successNotify && response.data.msg) {
      // 弹出成功提示
      Message.success(i18n.t(response.data.msg))
    }
    return Promise.resolve({
      code: response.data.code,
      msg: response.data.msg,
      data: response.data.data,
    })
  },
  function (error) {
    if (error.message.indexOf('timeout') > -1) {
      // 多语言需要自己在项目中配置
      Message.error('请求超时,请重试!')
    }

    return Promise.reject(error)
  },
)

// 请求拦截器
http.interceptors.request.use(
  function (config) {
    return config
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
  },
)


// 导入河段配置
export const riverConfigImportService = (data, config = {}) => {
  return http({
    method: 'post',
    url: '/aaaaaa/v1/riverConfig/import',
    config,
    data
  })
}

三、 axios 下载文件

  1. 请求的响应类型必须为 ‘arraybuffer’ 或者 ‘blob’
  2. 对后台返回的数据流做处理,让浏览器下载(可以看后面的例子)

3.1 后台定义上传和下载

var express = require('express');
var router = express.Router();
var fs = require('fs');
const path = require('path')
// 下载文件依赖的库
var multer  = require('multer');
// 文件储存路径
var upload = multer({dest: 'upload_tmp/'});

/**
 * upload 模块index
 * */
router.get('/', function(req, res, next) {
  res.render("upload/index",{
    title:"nodejs上传文件测试"
  });
});

// 上传文件
router.post('/upload',upload.any(), function(req, res, next) {
    console.log(req.files);  // 上传的文件信息
    var des_file = "./uploadfile/" + req.files[0].originalname;
    // 获取上传文件同时传递过来的参数
    console.log(req.body.name)
    fs.readFile( req.files[0].path, function (err, data) {
        fs.writeFile(des_file, data, function (err) {
            if( err ){
                console.log("error")
                console.log( err );
            }else{
                console.log("sucess")
                response = {
                    message:'File uploaded successfully',
                    filename:req.files[0].originalname
                };
                console.log( response );
                res.end( JSON.stringify( response ) );
            }
        });
    });
});

// 下载 get 请求
router.get('/loadimg', function(req, res, next) {
  console.log(req)
  let imgid = req.param('imgid');
  debugger
  let file = path.join(__dirname,'./222.png');
  console.log(file);
  res.download(file); 
});

// 下载 post请求
router.post('/loadimg', function(req, res, next) {
  console.log(req)
  let imgid = req.param('imgid');
  debugger
  let file = path.join(__dirname,'./222.png');
  console.log(file);
  res.download(file); 
});

module.exports = router;

3.2前端axios上传下载(ajax 处理下载文件)


<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <link rel="stylesheet" href="/public/css/bootstrap.min.css">
    <link rel="stylesheet" href="/public/css/hb_wap.css">
    <script src="/public/js/axios.min.js"></script>
    <title><%=title%></title>
</head>
<body >

<!-- <form action="/sqh/upload" method="post" enctype ="multipart/form-data"> -->
    <input type="file" name="myfile" id="fileInput"/>
    <button onclick="uploadAction()">上传图片</button> 
    <div>
        <button onclick="downloadGetAction()">下载图片 downloadGetAction</button> 
    </div>
    <div>
        <button onclick="downloadPostAction()">下载图片 downloadPostAction</button> 
    </div>
<!-- </form> -->

</body>
<script>
// 上传图片
function uploadAction () {
    var fileWidget = document.getElementById('fileInput')
    console.log(fileWidget)
    debugger
    let param = new FormData();
    param.append("name", "wiiiiiinney");
    let file = fileWidget.files[0]
    if (!file) {
        alert('请先选择上传的问题件')
        return false
    }
    //通过append向form对象添加数据
    param.append("file", file);
    //FormData私有类对象,访问不到,可以通过get判断值是否传进去
    console.log(param.get("file"));

    let config = {
        //添加请求头
        headers: { "Content-Type": "multipart/form-data" },
        //添加上传进度监听事件
        onUploadProgress: e => {
          var completeProgress = ((e.loaded / e.total * 100) | 0) + "%";
          this.progress = completeProgress;
        }
    };

    axios.post('http://127.0.0.1:3000/upload/upload', param, config).then( function (response) { 
        console.log(response);
        debugger
    })
    .catch(function (error) {
        console.log(error);
    });
}

// 下载图片
function downloadGetAction () {
    axios({
      method: 'GET',
      url: 'http://127.0.0.1:3000/upload/loadimg',
      // 设置 header 参数
      // headers: {
      //   'Access-Control-Expose-Headers': 'Content-Disposition'
      // },
      responseType: 'blob', // 一定要设置响应类型,否则不能正确处理响应的数据
      data: {
          myname: 'huangbiao',
          age: 18
      }
    }).then(function (res) {
    	// 判断后台是否返回了  文件名,没有就用时间戳命名
    	let fimeName = new Date().getTime() + '.png'
        if (res.headers['content-disposition']) {
          console.log(res.headers['content-disposition'])
          const contentDisposition = res.headers['content-disposition']
          if (contentDisposition) {
            const urlStr = contentDisposition.split('filename=')[1]
            fimeName = decodeURIComponent(urlStr)
          }
        }
        let blob = new Blob([res.data], {
        //   type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
        })
        let downloadElement = document.createElement('a')
        let href = window.URL.createObjectURL(blob) // 创建下载的链接
        downloadElement.href = href
        downloadElement.download = new Date().getTime + '.png' // 下载后文件名
        document.body.appendChild(downloadElement)
        downloadElement.click() // 点击下载
        document.body.removeChild(downloadElement) // 下载完成移除元素
        window.URL.revokeObjectURL(href) // 释放blob对象
      })
}

// 下载图片
function downloadPostAction () {
    axios({
      method: 'POST',
      url: 'http://127.0.0.1:3000/upload/loadimg',
      // 设置 header 参数, 可以添加token
      // headers: {
      //   'Access-Control-Expose-Headers': 'Content-Disposition'
      // },
      responseType: 'arraybuffer', // 一定要设置响应类型,否则不能正确处理响应的数据
      data: {
          myname: 'huangbiao',
          age: 18
      }
    }).then(function (res) {
        let blob = new Blob([res.data], {
        //   type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
        })
        let downloadElement = document.createElement('a')
        let href = window.URL.createObjectURL(blob) // 创建下载的链接
        downloadElement.href = href
        downloadElement.download = new Date().getTime + '.png' // 下载后文件名
        document.body.appendChild(downloadElement)
        downloadElement.click() // 点击下载
        document.body.removeChild(downloadElement) // 下载完成移除元素
        window.URL.revokeObjectURL(href) // 释放blob对象
      })
}
</script>
</html>

四、例子说明

4.1 后台下载使用get方法,前端使用<a>标签下载

// 使用GET 方法,实现文件的下载
downFileByGet (file) {
  var url = '/api/v1/event/download?documentUrl=' + file.url
  var a = document.createElement('a')
  a.href = encodeURI(url)
  a.setAttribute('target', '_blank')
  a.download = file.name
  a.click()
}

4.2 将字符串以文件的形式下载

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button onclick="downloadByBlob()">下载</button>
  </body>
  <script>
    //通过FileReader转化为base64字符串下载
    function downloadByBlob() {
      const content = '{a: "hb"}';
      let blob = new Blob([content], {
        type: "text/plain;charset=utf-8",
      });
      let reader = new FileReader();
      reader.readAsDataURL(blob);
      reader.onload = function(e) {
        let a = document.createElement("a");
        a.download = "a.txt";
        a.href = e.target.result;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      };
    }
  </script>
</html>

4.3 公司下载 excel 的办法

// Vue 下载触发的方法
downloadFile({ fileName: row.filePath }).then(res => {
	letfimeName = new Date().getTime() + '.xls'
      if (res.headers['content-disposition']) {
        console.log(res.headers['content-disposition'])
        const contentDisposition = res.headers['content-disposition']
        if (contentDisposition) {
          const urlStr = contentDisposition.split('filename=')[1]
          fimeName = decodeURIComponent(urlStr)
        }
      }
    // console.log(res)
    const blob = new Blob([res.data], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
    })
    const downloadElement = document.createElement('a')
    downloadElement.style.display = 'none'
    const href = window.URL.createObjectURL(blob) // 创建下载的链接
    downloadElement.href = href
    let fileName = row.name
    if (!fileName) {
      fileName = '模板' + moment().format('YYYY-MM-DD') + '.pdf' // 下载后文件名
    }
    downloadElement.download = fileName // 下载后文件名
    document.body.appendChild(downloadElement)
    downloadElement.click() // 点击下载
    document.body.removeChild(downloadElement) // 下载完成移除元素
    window.URL.revokeObjectURL(href) // 释放blob对象
    this.$message.success('下载成功')
  })
},

// API 请求设置
// 文件下载
export const downloadFile = params => {
  return http({
    method: 'get',
    url: `${BASE_URL}/download`,
    params,
    responseType: 'blob'
  })
}


// axios拦截器做的处理
// 文件下载 二进制流数据
if (response.request.responseType === 'blob') {
  if (response.data) {
    return Promise.resolve(response)
  } else {
    Message.error('文件不存在')
    return Promise.reject(response)
  }
}

在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐