一、需求
vue项目,要求通过接口获取第三方平台传输的文件流,无需下载,获取后转成文件自动上传到当前平台媒资库。
二、开发过程
1、问题1
现象:new blob([])后文件大小跟原文件大小不一样
原因:获取的文件流乱码导致的
解决:请求时加上responseType:‘blob‘
2、问题2
现象:加上responseType:‘blob‘无效,还是乱码
原因:Mock.js初始化的时候给拦截响应设置了responseType:’’
解决:注释掉Mock.js的使用
js通过url上传文件
//url转blob转File上传文件(音频、视频、图片)
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.onload = () => {
let content = xhr.response;
let blob = new Blob([content]);
let file = new File([blob], 'test.png', {type: 'image/png'});
let formData = new FormData();
formData.append('file',file);
}
xhr.send();
整合到自己代码中,因为设置了responseType: “blob”,所以返回的data就是blob文件流,不需要再转换了,如下:
//api文件中
download(id){
return request({
url: '/media/getMedia?id='+id,//这里使用当前平台监听接口进行模拟,
method: 'get',
responseType: "blob", //必须要填写
})
},
//jax文件中,url转blob转File后,再上传文件
autoDownUpLoad(row){
console.log(row)//row[0]-name row[7]-id row[8]-路径
this.$myfun.show_Loading()
this.$api.download(row[7]).then(data => {
var file = new File([data], row[1], {type:"audio/mpeg"});
console.log(data,file)
// 上传接口
const formData = new FormData()
formData.append('filefield', file)
formData.append('name', row[0]);
axios.post('/media/addAudio', formData, {
headers: {
'Content-Type': 'multipart/form-data',
'Referer_':location.hash.substr(1)
}
}).then(res => {
if (res.data.success) {
this.$message.success('添加成功');
}else{
this.$message.error(res.data.message)
}
this.getAjax()
this.$myfun.close_Loading()
})
})
}
上传时报错了,经排查发现上传的音频文件播放不了,于是一直排查问题。F12一看,浏览器拿到的不是Blob类型的,而是一串字符串乱码。
咱也看不懂这是个啥,也不知道是不是乱码,只知道是个字符串,于是各种百度转 blob,什么responseType: “blob”, 什么new Blob([data])还是无济于事,而且明明说加上responseType: "blob"后返回的就是blob文件流,为什么我的还是字符串?
于是我开始百度responseType:'blob’无效,发现了一个大佬,这里给出他博客链接:vue axios(下载文件流)设置返回值类型responseType:'blob’无效的问题
三、原因
----------“mock模块会影响原生的ajax请求,使得服务器返回的blob类型变成乱码”
--------
可以看到overrideMimeType()中mockjs初始化的时候给拦截响应设置了responseType:’’
// 初始化 Response 相关的属性和方法
Util.extend(MockXMLHttpRequest.prototype, {
responseURL: '',
status: MockXMLHttpRequest.UNSENT,
statusText: '',
// https://xhr.spec.whatwg.org/#the-getresponseheader()-method
getResponseHeader: function(name) {
// 原生 XHR
if (!this.match) {
return this.custom.xhr.getResponseHeader(name)
}
// 拦截 XHR
return this.custom.responseHeaders[name.toLowerCase()]
},
// https://xhr.spec.whatwg.org/#the-getallresponseheaders()-method
// http://www.utf8-chartable.de/
getAllResponseHeaders: function() {
// 原生 XHR
if (!this.match) {
return this.custom.xhr.getAllResponseHeaders()
}
// 拦截 XHR
var responseHeaders = this.custom.responseHeaders
var headers = ''
for (var h in responseHeaders) {
if (!responseHeaders.hasOwnProperty(h)) continue
headers += h + ': ' + responseHeaders[h] + '\r\n'
}
return headers
},
overrideMimeType: function( /*mime*/ ) {},
responseType: '', // '', 'text', 'arraybuffer', 'blob', 'document', 'json'
response: null,
responseText: '',
responseXML: null
})
四、总结大佬们的解决方案:
1、别用 mockjs了,找到引入mockjs的地方import、require给注释掉
2、改下源码
dist/mock.js
大约在 8683 行,加一行代码
this.custom.xhr.responseType = this.responseType
3、但离谱的是,我的项目mock.js是在index.html中引入的,一旦注释掉,使用Mock.mock(url, 'get', (res) => { })
的文件就会报错,于是我们看了一下报错,Mock is undefined,此时应该是明白了,没有引入当然会报错了,于是我们把使用了mockjs来模拟请求后端接口获得数据的文件注释掉了,即用到Mock.mock(url, 'get', (res) => { })
的文件,测试一下,终于搞定了。