文件下载 Content-Disposition中filename中文乱码解决

1. 通过链接直接下载

后端代码:

	response.setCharacterEncoding(StandardCharsets.UTF_8.name()); // 字符集编码
	response.setContentType("application/octet-stream"); // 返回内容的MIME类型
	response.addHeader("Content-disposition", "attachment;filename=" + fileName + ";filename*=UTF-8" + fileName); // 内容描述
	response.addHeader("Access-Control-Allow-Origin", "*"); // 实现跨域
    /**
     * 编码格式转换
     *
     * @param request 请求
     * @param pFileName 文件名称
     * @return String
     * @throws UnsupportedEncodingException
     */
    private String encodeChineseDownloadFileName(HttpServletRequest request, String pFileName)
            throws UnsupportedEncodingException {
        String filename;
        String agent = request.getHeader("USER-AGENT");
        if (null != agent) {
            if (-1 != agent.indexOf("Firefox")) {
                filename = "=?UTF-8?B?" + (new String(Base64.decode(pFileName.getBytes(StandardCharsets.UTF_8)))) + "?=";
            } else if (-1 != agent.indexOf("Chrome")) {
                filename = new String(pFileName.getBytes(), StandardCharsets.ISO_8859_1);
            } else {//IE7+
                filename = URLEncoder.encode(pFileName, StandardCharsets.UTF_8.name());
            }
        } else {
            filename = pFileName;
        }
        return filename;
    }

前端代码:

  const elink = document.createElement('a') // 创建a标签
  // elink.download = fileName // 重命名文件
  elink.style.display = 'none'
  elink.href = url
  document.body.appendChild(elink)
  elink.click() // 触发链接
  document.body.removeChild(elink)
2. 通过数据流下载

通过数据流下载,下载时的文件名称就和Content-disposition中的filename关系不大
后端代码:

	fileName = URLEncoder.encode(pFileName, StandardCharsets.UTF_8.name());
	response.setCharacterEncoding(StandardCharsets.UTF_8.name()); // 字符集编码
	response.setContentType("application/octet-stream"); // 返回内容的MIME类型
	response.addHeader("Content-disposition", "attachment;filename=" + fileName + ";filename*=UTF-8" + fileName); // 内容描述
	response.addHeader("Access-Control-Allow-Origin", "*"); // 实现跨域
	// 列表哪些header可以作为响应的一部分暴露给外部(除了默认的七种,其他的是不暴露给外部的)
	response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); 

前端代码:

getFileName(fileName, response) {
  // 需要响应设置此header暴露给外部,才能获取到
  let contentDisposition = response.headers['content-disposition']
  if (contentDisposition) {
  	// 正则获取filename的值
    let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
    let matches = filenameRegex.exec(contentDisposition)
    if (matches != null && matches[1]) {
      fileName = matches[1].replace(/['"]/g, '')
    }
    // 通过 URLEncoder.encode(pFileName, StandardCharsets.UTF_8.name()) 加密编码的, 使用decodeURI(fileName) 解密
    fileName = decodeURI(fileName)
    // 通过 new String(pFileName.getBytes(), StandardCharsets.ISO_8859_1) 加密编码的, 使用decodeURI(escape(fileName)) 解密
    // fileName = decodeURI(escape(fileName))
  }
  return fileName
}

通过数据流下载文件:https://blog.csdn.net/besto229/article/details/112305428

  • 9
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值