之前写过一篇发送文件消息的,原生input上传文件(聊天发送文件消息),这次的需求就是更改上传地址,使用阿里云OSS上传。
如果想了解阿里云对象存储OSS是如何使用的,请看阿里云存储对象OSS使用讲解一:OSS的购买和配置。
那么,这次选择使用elementUI的upload插件,样式各位大哥根据自己的需求实现吧,就不做展示了。
要使用OSS,首先需要安装,引入,创建,这里就不详解了,推荐查看:阿里oss前端上传使用。
这位大哥是基于promise来创建OSS,也可以选择不使用Promise:
data(){
return {
ossConfig: { // ossConfig 的内容根据自己项目自己添加。
region: '',
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
accessKeyId: '',
accessKeySecret: '',
bucket: '',
ossDomain: ""
},
client: {},
tempCheckpoint: "",
fileList: [],
processPercent: {},
extImag:{
".zip":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1602681161979&di=78bc24f85f33acd6c61c04047624a331&imgtype=0&src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F00%2F22%2F11%2F7256ce730033d96.jpg",
".rar":"",
}
}
},
created() {
let client = new OSS(this.ossConfig);
this.client = client
},
文件上传:
methods:{
async multipartUpload (fileObj,ossSavePath,fileName,ext){
let uid = fileName
this.$set(this.processPercent,uid,0)
try {
let self = this;
let result = await this.client.multipartUpload(ossSavePath, fileObj
// 以下参数皆为可选参数,可不传
,{
progress: function (p, checkpoint) { // 如果需要显示上传进度则需要使用progress函数
self.$set(self.processPercent,uid,Math.floor(p*100)) // 在页面中获取processPercent.uid即为上传进度
// 断点记录点。浏览器重启后无法直接继续上传,您需要手动触发上传操作。
self.tempCheckpoint = checkpoint;// 记录上传断点
},
meta: { year: 2020, people: 'test' },
mime: fileObj.type,
headers: {
"Content-Disposition": `attachment; filename=${encodeURIComponent(fileObj.name)}`,
"Cache-Control": "public, no-cache"
}
})
let data = {
url:this.ossConfig.ossDomain+result.name,
fileName:fileName,
ext:ext
}
return data;
} catch(e){
console.log(e);
}
},
uuid(){ // 类似于获取随机字符段
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
},
uploadFile(data){
let uid = this.uuid()
let fileObj = data.file;
let fileName = fileObj.name
let pos = fileName.lastIndexOf('.')
let lastName = fileName.substring(pos, fileName.length)
let ossSavePath = this.OssSaveDir+uid+lastName;
let accept = this.accept.split(",");
let isAllow = accept.indexOf(lastName)
if(isAllow==-1){
this.$message.error(`${this.acceptTips}`);
return false
}
const isOverLimit500M = (fileObj.size /1024/1024/100) <= 5
if (!isOverLimit500M) {
this.$message.error('上传文件不得大于500MB!')
return false
}
let result = this.multipartUpload(fileObj,ossSavePath,fileObj.uid,lastName)
result.then((data)=>{
debugger
console.log(data)
let item = {
"name":fileObj.name,
"url":data.url,
"fileName":data.fileName,
"ext":data.ext,
"uid":fileObj.uid
}
this.fileList.push(item)
this.$emit('fileList', this.fileList);
})
},
}
本篇重点:请求头
如果不传 headers 参数,可能会出现两种情况:
- 返回的文件链接为查看,而非下载链接【文件类型(txt/doc等)可能会出现,而非图片】
- 点击下载文件,保存弹框中显示文件名称不正确
针对这两个问题,重点就是在于设置请求头信息:Content-Disposition。
Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件,Content-Disposition 属性是作为对下载文件的一个标识字段。
通俗来讲就是Content-disposition属性决定你在浏览器窗口打开上传成功后返回的文件链接时,浏览器如何响应,是直接在页面显示文件内容,还是下载文件。
Content-Disposition属性有两个值:
- inline:在浏览器显示打开文件(显示内容)
- attachment:弹出文件下载保存框(下载文件)
而如果直接设置属性值为attachment,下载文件可能显示的文件名不正确,这个时候就需要Content-disposition属性控制用户请求所得的内容存为一个文件的时候提供一个默认的文件名,那么就需要传递文件名,综上所述,重点如下:
// 设置请求头 headers: { "Content-Disposition": `attachment; filename=${encodeURIComponent(fileObj.name)}` }
如果感觉我讲的不清楚的,推荐两篇文章:
header中Content-Disposition的作用与使用方法。
而为何使用 encodeURIComponent() 方法,就不做详述了,原因如下:
那么,最重要的还是文档,上文档:阿里云 ali-oss 文档。
本篇完~-~
另附一篇:这个文件下载问题难住了我至少三位同事。