You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为document类型元数据请求添加XCompanyAccessToken请求头?

问题描述

我需要用JavaScript和Fetch API实现带认证的文件下载功能,但浏览器会自动发起一个document类型的元数据请求,这个请求未携带必要的自定义请求头XCompanyAccessToken中的访问令牌,导致后端无法生成待下载的文件。


当前代码

我目前使用的是网上找到的代码:

function download(fileUrl) {
  let fileName;
  fetch(fileUrl, {
        method: 'GET',
        headers: {
          'XCompanyAccesstoken': '<access-token>',
          /* 其他请求头,此处省略 */
        },
        mode: 'cors',
    })
  // 下面的then块仅处理gzip压缩的文件,保留下来是为了完整展示
  .then(response => {
            const contentEncodingHeader = response.headers?.get('Content-Encoding');
            if (contentEncodingHeader === 'gzip') {
                // 解析Content-Disposition获取文件名
                const contenDispositionHeader = response.headers?.get('Content-Disposition');
                const fileNameSplit = contenDispositionHeader?.split('filename=')?.[1];
                // 移除首尾双引号
                fileName = JSON.parse(fileNameSplit ?? '""');
                return response.blob();
            }
            return null;
        })
        .then(blobby => {
            if (blobby) {
                const objectUrl = window.URL.createObjectURL(blobby);

                anchor.href = objectUrl;
                anchor.download = fileName;
                anchor.click();

                window.URL.revokeObjectURL(objectUrl);
            }
        })
}

这些请求头在fetch类型的请求中能正确设置,但在document类型的元数据请求里缺失。

后端已暴露必要的响应头:

access-control-expose-headers: Content-Disposition, Content-Encoding

且响应头设置正确:

content-disposition: attachment; filename="2022-10-12_13-12_download.csv"
content-type: text/csv; charset=UTF-8

(注:未设置content-encoding头)

目前会向后端发起三次请求:

  • 预检请求(正常执行)
  • 元数据请求(需要令牌但未携带)
  • Fetch请求(携带令牌)

已尝试方案

我试过用各种关键词搜索,比如how can i add a custom header to the fetching of metadata for downloads?,未找到相关解决方案。

另外注意到浏览器发送元数据请求时会携带Cookie,因此尝试用代码将访问令牌添加到Cookie中,但Cookie头未包含该设置的Cookie,此方法无效。


最终问题
  1. 是否有办法解决此问题?
  2. 能否让浏览器发起document类型的元数据请求时,带上自定义的XCompanyAccessToken请求头?
  3. 是否需要对后端进行相应修改?

解决方案

方案1:跳过元数据请求,完全通过Fetch控制下载流程

浏览器发起元数据请求是因为通过anchor.click()触发了默认下载行为,浏览器会提前请求文件元数据。可以直接在Fetch拿到Blob后创建下载链接并触发下载,全程由Fetch控制,避免浏览器发起额外请求。

针对你的场景(无gzip压缩),简化后的代码如下:

function download(fileUrl) {
  fetch(fileUrl, {
    method: 'GET',
    headers: {
      'XCompanyAccesstoken': '<access-token>'
    },
    mode: 'cors'
  })
  .then(response => {
    if (!response.ok) throw new Error('请求失败');
    // 解析文件名
    const disposition = response.headers.get('Content-Disposition');
    let fileName = 'download.csv';
    if (disposition) {
      const match = disposition.match(/filename="?([^"]+)"?/);
      if (match) fileName = match[1];
    }
    return response.blob();
  })
  .then(blob => {
    const objectUrl = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = objectUrl;
    a.download = fileName;
    a.click();
    URL.revokeObjectURL(objectUrl);
  })
  .catch(err => console.error('下载失败:', err));
}

这种方式下,浏览器只会发起Fetch请求(含预检请求),不会触发额外的元数据请求,因为下载是通过Blob创建的本地URL触发,而非直接指向远程资源。

方案2:后端配合,改用Cookie传递认证令牌

如果必须保留浏览器的元数据请求,只能改用Cookie传递令牌。此前用JS设置Cookie失败,大概率是因为Cookie的SameSite、Secure、Domain等属性不符合要求,或域名不匹配。

需要后端配合修改:

  • 后端设置Cookie时指定正确的Domain、Path、SameSite(如SameSite=Strict或Lax)、Secure(HTTPS环境下)属性;
  • 后端修改认证逻辑,优先从Cookie中读取XCompanyAccessToken的值;
  • 前端通过后端接口设置Cookie,而非直接用JS操作(避免跨域或属性限制)。

方案3:后端对元数据请求跳过认证检查

如果元数据请求仅用于获取文件名、文件大小等基础信息,可让后端对document类型的请求跳过认证检查,仅对实际下载的Fetch请求做认证。但此方式存在安全风险,需评估是否允许未认证用户获取文件元数据。


内容的提问来源于stack exchange,提问作者Dominik Reinert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 13:45:32