上传文件到服务器(前端+后端)

2,878 阅读2分钟

前后端(Vue + Node)实现上传文件并保存到服务器。input + axios + body-parser + fs 模块 读取写入数据。

前端

部分为 Vue 代码

使用 input(file)标签

<input name="file" type="file" multiple 
       ref="file" 
       @change="change"/>
<button @click="submit">上传</button>

参数解释

参数名意义
multiple是否可以一次选择多个文件
type = "file"设置后选择文件,可以得到一个 File 对象
$refs.file.valueinput 的值为上传文件在本地的绝对地址
@change选择的文件发生变化时触发的事件

File 对象

前端上传二进制文件就靠这个对象了。如果直接打印File对象可以得到文件名,读取时间大小等信息 ....

特别注意!这些信息都是只读的,不可直接修改。

function change (e) {
	// files 数组
	const files = e.target.files;
	console.log(files)
	for (const file of files) {
		// file 对象
		console.log(file)
	}
}

File 对象

file对象

File 对象数组

files数组

* FileReader 对象

读取 File 对象(文件)的二进制数据

特别注意!FileReader.readAsBinaryString() 方法,我在使用中经常出问题,不建议使用。

function change (e) {
	const files = e.target.files;
	for (const file of files) {
  		// 读数据
		let fr = new FileReader();
        // 读为文本
        // fr.readAsText(file)
        // 读为图片(Base64编码)
        // fr.readAsDataURL(file)
        // 读为二进制流
		fr.readAsArrayBuffer(file)
        // FileReader 对象的事件
        // 读取成功
        fr.onload = () => {
            // 读取到的 ArrayBuffer
            console.log(fr.result)
        }
        // 读取失败
        fr.onerror = () => {
            alert('Oop!error...')
        }
        // 读取结束(不管成功还是失败)
        fr.onloadend = () => {
            console.log('End...')
        }
	}
}

* Axios 发送 ArrayBuffer 对象

ArrayBuffer 是无法直接发送出去的,需要转换为 Json 对象后发出。

这里提供一个转换函数

function ArrayBufferToJson (arrayBuffer) {
	const buffer = new Buffer(arrayBuffer.byteLength);
      const view = new Uint8Array(arrayBuffer);
      for (let i = 0; i < buffer.length; ++i) {
        buffer[i] = view[i];
      }
    return buffer.toJSON()
}
// 把文件数据和要发给后端的其他信息放入一个对象中
let sendObj = {
    uid: 001,
    name: ’NiChengKai的测试文件‘,
    // 使用上面的函数
    data: this.ArrayBufferToJson(fr.result)
}

以 Json 形式发送

由于数据很大,所以只能POST

let {data: res} = await axios.post('后端地址', sendObj, {
    headers: {
        // 关键
        'Content-Type': 'application/json'
    }
});

完整代码

html

<input name="file" type="file" multiple/>
<button>上传</button>

js

// 准备发送数据的数组
let sendList = [],
// 结果数组
let resultList = [],

// 转换函数
function ArrayBufferToJson (arrayBuffer) {
	const buffer = new Buffer(arrayBuffer.byteLength);
      const view = new Uint8Array(arrayBuffer);
      for (let i = 0; i < buffer.length; ++i) {
        buffer[i] = view[i];
      }
    return buffer.toJSON()
},
// 选择文件
function change (e) {
	const files = e.target.files;
	for (const file of files) {
		let fr = new FileReader();
		fr.readAsArrayBuffer(file)
        fr.onload = () => {
            let sendObj = {
                uid: 001,
                name: ’NiChengKai的测试文件‘,
                data: ArrayBufferToJson(fr.result)
            }
            sendList.push(sendObj)
        }
        fr.onerror = () => {
            alert('Oop!error...')
        }
        fr.onloadend = () => {
            console.log('End...')
        }
	}
}
// 上传
function submit () {
    for (const sendObj of sendList) {
       let {data: res} = await axios.post('后端地址', sendObj, {
           headers: {
               'Content-Type': 'application/json'
           }
       });
        resultList.push(res)
    }
    sendList = [],
    // 记得清除 input 的数据
}

后端

后端我使用的是 Node + Express

跨域设置

这是常规,就不多说了

安装

npm install cors -S

引入

// app.js
// 跨域配置
const cors = require('cors');
// noinspection JSCheckFunctionSignatures
app.use(cors({
	origin: '*',
	optionsSuccessStatus: 200
}));

配置 body-parser 中间件

由于使用了 POST请求 ,需要配置 body-parser 中间件解析 POST请求 的参数。

安装

npm install body-parser -S

引入

// app.js
const bodyParser = require('body-parser');
// 设置解析为 Json 格式并设置数据最大限制
app.use(bodyParser.json({
	limit: '40mb'
}))

读取二进制数据

// 需要导入 fs 模块
router.post('/', (req, res) => {
	// result 为二进制数据
	let {uid, name, result} = req.body;
	// 把字符串形式的 Buffer 填充入 Buffer 对象中
	result = Buffer.from(result)
	// 写文件
	fs.writeFile('文件路径', (result, err) => {
		if (!err) {
			res.send(name + ' 上传成功!')
		} else {
			res.send(name + '上传失败!')
		}
	})

})