uploader组件配合egg node使用form-data文件上传服务

9 篇文章 0 订阅
3 篇文章 0 订阅

uploader + node 进行文件上传服务

技术栈

文档类上传(.xlsx .xls .docx .doc .pdf)

前端的处理
<a-upload
	accept=".xlsx .xls .docx .doc .pdf"
	:file-list="fileList"
    :before-upload="beforeUpload"
    :custom-request="customRequest"
    @change="onChange"
>上传</a-upload>
export default Vue.extend({
	data() {
        return {
            fileList: [] as any, // 上传列表
        };
	},
	methods: {
		// 上传之前 可以对文件做一些限制和校验(比如名字, 类型等)
        beforeUpload(file) {
        	console.log('file:', file);
        	// 返回false 停止上传
            if (file.name.length > 128) return false; // 若返回 false 则停止上传
        },

		// 上传文件改变时的状态
        onChange({ file, fileList }) {
	        console.log(file.status);
            // 若每次只支持上传一个文件, 可以限制上传列表数量为1个
            fileList = fileList.slice(-1);
            fileList = fileList.map(file => {
                if (file.response) file.url = file.response.url;
                return file;
            });
            // 过滤掉错误的文件
            this.fileList = fileList.filter(file => !!file.status);
        },

		// 上传
		async customRequest(option) {
			console.log('option', option);
			try {
			    const formData = new FormData().append('file', option.file);
			    const data = await http.post('/upload', formData, {
			    	headers: { 'Content-Type': 'multipart/form-data' }
			    	});
			    option.onSuccess();
			} catch(err) {
			    option.onError(err);			
			}
		}
	}
})

说明:

一、customRequest中的option参数, 除携带当前文件的信息外, 还有处理三种状态的回调可供选择
在这里插入图片描述
二、这里用到的请求(http)是我当前项目中axios封装的请求, 实际开发中, 替换成你们自己的axios请求和对应的接口

node端的处理
router
module.exports = (app) => {
    const { controller, router } = app;
    const v1 = router.namespace('/v1');
    v1.resources('uploader', '/upload', controller.upload);
}
controller
// controller/uploader.js
const { Controller } = require('egg');
class Uploader extends Controller {
    async create() {
        const { ctx, service } = this;
        const file = ctx.request.files[0];
        // 获取文件类型
        const index = file.filename.lastIndexOf('.');
        const fileType = file.filename.slice(index + 1);
        const data = await service.appTest.upload(file, fileType);
        ctx.body = data;
    }
}
module.exports = Uploader;
service
// service/uploader.js
const { Service } = require('egg');
const FormData = require('form-data');
const fs = require('fs');

class Uploader extends Service {
    async upload(file, fileType) {
        const formData = new FormData();
        const { filename } = file;
        const readStream = fs.createReadStream(file.filepath);
        formData.append('file', readStream, { filename });
        formData.append('file_type', fileType);
        formData.append('file_name', file.filename);
        // 设置content-length:
        const length = await new Promise((resolve) => {
            formData.getLength((err, length) => {
                if (err) return;
                resolve(length);
            });
        });
        const formHeaders = formData.getHeaders();
        formHeaders['Content-Length'] = length;
        const data = await this.ctx.axios.post(
        	`/java/upload`, // 后端的接口
	        formData,
    	    { headers: formHeaders }
    	);
        return data;
    }
}
module.exports = Uploader;

说明:

一、这里使用了egg-router-plus插件, 是为了解决路由过多的问题, 可以单独给每个模块开辟一个命名空间, 感兴趣可以点击查看
二、为了方便 这里使用了RESTful 的方式来定义路由
三、controller中获取的web传过来的file信息:

在这里插入图片描述
四、读取成readStream后, 最终传给后端的formaData
在这里插入图片描述


图片类上传(.png .jpg)

注意: 这里其实想介绍下图片预览的功能preview(其他在文档类上传中重复过的步骤, 这里就不再赘述了)

前端的处理
<a-upload-dragger
    name="image"
    accept=".img,.png"
    list-type="picture-card"
    :show-upload-list="{showRemoveIcon:false,showPreviewIcon:true}"
    @preview="onPreview"
    :file-list="fileList"
    :before-upload="beforeUpload"
    :custom-request="customRequest"
    @change="onChange"
></a-upload-dragger>
<a-modal :visible="previewVisible" :footer="null">
	<img :src="previewImage" />
</a-modal>

<!-- 后面四个/ fileList / beforeUpload / customRequest / onChange 相关逻辑就不再赘述了 -->
data() {
	return {
		previewImage: '',
		previewVisible: false,
	};
},
methods: {
    getBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => resolve(reader.result);
            reader.onerror = error => reject(error);
        });
    },
    // 图片预览功能
    async handlePreview(file) {
    	console.log(file);
        if (!file.url && !file.preview) {
            // 如果没有图片路径, 则直接拿图片base64给src
            file.preview = await this.getBase64(file.originFileObj);
        }
        // 打开预览弹窗
        this.previewImage = file.url || file.preview;
        this.previewVisible = true;
    },

	// 上传
	async customRequest(option) {
		// 不再赘述, 与文档类上传一致
	}
}

说明

一、预览函数 onPreview 获取到的参数信息:
在这里插入图片描述
二、上传图片预览效果:
在这里插入图片描述

另: upload组件部分属性(详情见官网)

API说明类型默认值
accept接受上传的文件类型string
customRequest自定义上传方法Function
fileList已经上传的文件列表(受控)object[ ]
name发到后台的文件参数名string‘file’
listType上传列表的内建样式,支持三种基本样式 text, picture 和 picture-cardstring‘text’
showUploadList上是否展示 uploadListBoolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean }true
remove点击移除文件时的回调Function(file): boolean | Promise
事件说明回调参数默认值
change上传文件改变时的状态Function
preview点击文件链接或预览图标时的回调Function(file)
reject拖拽文件不符合 accept 类型时的回调Function(fileList)

好啦~今天就分享到这里!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值