XMLHttpRequest 下载文件

2,471 阅读1分钟

前端主要代码

const xhr = new XMLHttpRequest();
xhr.onload = function (e) {
    const blob = new Blob([xhr.response], { type: "application/octet-stream" }); 
    const contentDisposition = xhr.getResponseHeader("Content-Disposition");
    let link = document.createElement("a");
    let fileName = "unknow.xxx";
    if (contentDisposition) {
        const descArrays = contentDisposition.split("=");
        fileName = decodeURI(descArrays[1]);
    }
    link.href = window.URL.createObjectURL(blob);
    link.download = fileName;
    link.click();
    link.remove();
    window.URL.revokeObjectURL(link.href);
}
// xhr.responseType = "blob";
// GET | POST |...
xhr.open(method, url);
// no param | FormData | json string | ...
xhr.send(params);

Java头信息设置

public static final String CONTENT_DISPOSITION = "Content-Disposition";
/**
 * 设置下载时http头信息
 *
 * @param response  HttpServletResponse
 * @param len       ContentLength
 * @param mediaType ContentType
 * @param fileName  File Name
 * @see org.springframework.http.MediaType
 */
public static void setDownloadHeader(HttpServletResponse response, int len, 
		MediaType mediaType, String fileName) {
    if (mediaType == null) {
        mediaType = MediaType.APPLICATION_OCTET_STREAM;
    }
    // try catch
    fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
    response.setCharacterEncoding(StandardCharsets.UTF_8.name());
    response.setContentLength(len);
    response.setContentType(mediaType.toString());
    response.setHeader("Pragma", "No-cache");
    response.setHeader("Cache-Control", "no-cache");
    response.setDateHeader("Expires", 0);
    response.setHeader(CONTENT_DISPOSITION, "attachment;filename=" + fileName);
    // 允许客户端访问一些头部信息
    response.addHeader("Access-Control-Expose-Headers", CONTENT_DISPOSITION);
}

参考与说明

  1. new Blob(...)不设置 type,而下载又没有写文件类型后缀,chrome会默认当做txt格式
  2. Content-Disposition默认不暴露给客户端,需要后端进行设置(见上文),参考: Access-Control-Expose-Headers | MDN
  3. 不给a标签download属性设置文件名,则浏览器会给出警告 Resource interpreted as Document but transferred with MIME type ...