前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot + Vue 前后端分离项目下载视频文件踩坑记录

SpringBoot + Vue 前后端分离项目下载视频文件踩坑记录

作者头像
Demo_Null
发布2020-09-28 11:21:31
7740
发布2020-09-28 11:21:31
举报
文章被收录于专栏:Java 学习Java 学习

☞ 背景

  项目服务端用的是 SpringBoot + SpringCloud + SpringDataJPA,前端用的是 Vue,有一个功能需要下载从监控中截取的视频(mp4),该视频由另一程序截取好放在某一目录下,使用 nginx 进行访问跳转,例如:视频:http://xx.xx.xx.xx:81/videoPath、web: http://xx.xx.xx.xx

☞ 坑一:a 标签

代码语言:javascript
复制
let link = document.createElement('a')
link.setAttribute('download', this.videoPath)
link.style.display = 'none'
link.href = this.url
document.body.appendChild(link)
link.click();

  使用该种方式直接将视频给打开了,没有下载视频,开始我以为是 download 属性写错了,后来发现是 url 指向第三方资源,download 属性失效了。

☞ 坑二:downloadjs 插件

  百度了一圈解决方案之后发现了 downloadjs 插件,觉得挺不错然后后开始了踩坑。安装 npm install downloadjs --save

代码语言:javascript
复制
import download from 'downloadjs'

function() {
	download(this.url);
}

  emmmm… 不出意外,又掉坑里了,他说我跨域了!好嘛,那就解决跨域,nginx 来一波,成功弹出下载框了,看到秒下完,顿时感觉不对。一看只有几 K,不死心的点开看了下,接受了下图的嘲讽。

在这里插入图片描述
在这里插入图片描述

☞ 坑三:responseType: blob

  经过一番查询没找到有效解决方案,加上时间问题我决定直接在后端写个 IO 来搞定下载问题。

代码语言:javascript
复制
@RestController
@RequestMapping("/download")
public class Download {
    @PersistenceContext
    private EntityManager entityManager;

    @Value("${param.url.disk}")
    public String disk;

    @RequestMapping("/video")
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    															 throws ServletException, IOException {
        String id = request.getParameter("id");
		
		// 参数合法性
        if (Objects.isNull(id) || StringUtils.isEmpty(id)) {
            return;
        }

		BaseDAOImpl<Info, Long> infoDao = new BaseDAOImpl<>(Info.class, entityManager);
        Info info = infoDao.findOne(Long.parseLong(id));

        String filename = info.getVideoPath();
        String realPath = disk + info.getPicturePath() + File.separatorChar + filename;
        FileInputStream fis = new FileInputStream(realPath);

        // 设置response的响应头
        String mimeType = servletContext.getMimeType(filename);
        response.setHeader("content-type",mimeType);
        String agent = request.getHeader("user-agent");
        filename = DownLoadUtils.getFileName(agent, filename);
        response.setHeader("content-disposition","attachment;filename=" + filename);

        ServletOutputStream sos = response.getOutputStream();
        byte[] buff = new byte[1024 * 8];
        int len = 0;
        while((len = fis.read(buff)) != -1){
            sos.write(buff,0,len);
        }

        fis.close();
    }
}
代码语言:javascript
复制
operateEvent(data) {
	down("/weChat/download/video" , {id: data.id}).then(response => {
			 this.saveAs(new Blob([response.data], { type: 'text/plain;charset=UTF-8' }), filename);
	});

},

// 导出文件函数
saveAs (obj, fileName) {
	let ele = document.createElement('a');
	ele.download = fileName || '下载';
	ele.href = URL.createObjectURL(obj);	// 绑定a标签
	ele.style.display = 'none';
	document.body.appendChild(ele);	// 兼容火狐浏览器
	ele.click();
	setTimeout(function () {	// 延时释放
		URL.revokeObjectURL(obj);	// 用 URL.revokeObjectURL() 来释放这个object URL
		document.body.removeChild(ele);	// 兼容火狐浏览器
	}, 100);
},

  成功弹出下载框,但是!!!后缀居然是 txt,直接给我干蒙了,什么鬼,为什么会是 txt 文件,经过一番 debug 后,发现混进来一个奇怪的东西。

在这里插入图片描述
在这里插入图片描述

  data居然乱码了。仔细查找一番后发现,在项目中我们封装了 HTTP 请求组件,他是这个坑的根源 ~ 有木有发现少了啥,没有写返回类型 ╯︿╰

代码语言:javascript
复制
export function fetch(url, data = {}) {
  return new Promise((resolve, reject) => {
    //debugger;
    axios.defaults.headers["Authorization"] = "Bearer " + sessionStorage.getItem('token');
    axios.defaults.headers["ClientType"] = global_variable.Wise.ClientType;
    axios({url: base + url, method: 'GET', params: data})
      .then(response => {
        resolve(response);
      })
      .catch(error => {
        reject(error);
      })
  });
}

  赶紧写上一个给加上 responseType: ‘blob’,测试通过。对于毕业一年在一家小公司既写前端又写后端的我来说,真的是一把辛酸泪。

代码语言:javascript
复制
export function down(url, data = {}) {
  return new Promise((resolve, reject) => {
    axios.defaults.headers["Authorization"] = "Bearer " + sessionStorage.getItem('token');
    axios.defaults.headers["ClientType"] = global_variable.Wise.ClientType;
    axios({url: base + url, method: 'GET', params: data, responseType: 'blob'})
      .then(response => {
        resolve(response);
      })
      .catch(error => {
        reject(error);
      })
  });
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-06-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ☞ 背景
  • ☞ 坑一:a 标签
  • ☞ 坑二:downloadjs 插件
  • ☞ 坑三:responseType: blob
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档