一、需求

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类型的,而是一串字符串乱码。

responseType中arraybuffer和bob区别 responsetype 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

responseType中arraybuffer和bob区别 responsetype blob问题_Data_02


3、但离谱的是,我的项目mock.js是在index.html中引入的,一旦注释掉,使用Mock.mock(url, 'get', (res) => { })的文件就会报错,于是我们看了一下报错,Mock is undefined,此时应该是明白了,没有引入当然会报错了,于是我们把使用了mockjs来模拟请求后端接口获得数据的文件注释掉了,即用到Mock.mock(url, 'get', (res) => { })的文件,测试一下,终于搞定了。