解决移动端H5下载文件提示文件类型无法识别或非法文件的问题

8,333 阅读2分钟

解决移动端H5下载文件提示文件类型无法识别或非法文件的问题

前几天做了H5移动端的下载文件功能,下载excel,用了最普通的下载的方法,异步请求文件下载链接,动态创建a标签进行下载,在PC端表现正常,在移动端一直提示非法链接,非法文件,无法识别文件类型等,安卓和IOS都是这样,最终通过改变响应头的content-type得以解决。

前端代码

/**
 * 很普通的网页下载文件的代码
 */
const downloadFile = async function () {
  const { data } = await Axios('/api/download/file/1000')
  const url = data.url
  const downloadlink = document.createElement('a')
  documentLink.href = url
  downloadlink.download = '今日数据.xlsx'
  downloadlink.style.display = 'none'
  downloadlink.click()  
}

后端代码

起初后端请求文件流的接口响应头 content-type的值为application/vnd.ms-excel,这是.xls文件的默认后缀,而文件真实的后缀是.xlsx,这个两种文件差别不大,PC端确实是不区分的,都是电子表格文件,但是移动端比较严格,后缀名和mime类型必须对应上,不然就会提示无法识别文件

office各种格式的mime类型大全

content-type的值修改成application/vnd.openxmlformats-officedocument.spreadsheetml.sheet后,移动端各浏览器均可以正常下载了,iphone因为本身的特殊性,仅能预览,另外只修改文件流的后缀也能解决部分问题,部分安卓可以,但是IOS比较严格,必须要修改content-type才能用

处理IphoneXR的safari浏览器在显示中文文件名时会乱码

在iphone XR 的safari上,点击下载,会弹出下载框,且文件名的中文部分会乱码,目前仅在XR的safari发现此问题,同样的,也是通过设置后端的响应头来解决的

iphone下载

代码如下

public class DownloadServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // codes..
        String name = "中文名 带空格 的测试文件.txt";
        String userAgent = request.getHeader("User-Agent");
        byte[] bytes = userAgent.contains("MSIE") ? name.getBytes() : name.getBytes("UTF-8"); // name.getBytes("UTF-8")处理safari的乱码问题
        name = new String(bytes, "ISO-8859-1"); // 各浏览器基本都支持ISO编码
        response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", name)); // 文件名外的双引号处理firefox的空格截断问题
        // codes..
    }
}

这段代码处理了文件下载时不同浏览器解析中文文件名所出现的乱码问题和firefox的空格截断问题,在IE9, chrome, opera, safari, firefox下均测试通过。

上述代码的链接在此兼容各浏览器的文件下载时中文名称乱码的解决方案