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

CRM Online 8.2中如何向HTML Web Resource传递ArrayBuffer实现文件下载

针对你在CRM Online 8.2里遇到的文件下载问题,我整理了几个可行的解决方案,适配CRM的沙箱限制和参数传递规则:

方案1:将ArrayBuffer转Base64字符串传递给WebResource

既然customParameters只能传字符串,我们可以把ArrayBuffer转成Base64编码,再传递给你的Shared/Download页面,在页面内解码后生成Blob触发下载。

表单脚本端(获取ArrayBuffer后处理):

// ArrayBuffer转Base64的工具函数
function arrayBufferToBase64(buffer) {
  let binary = '';
  const bytes = new Uint8Array(buffer);
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}

// 假设你已经拿到了arraybuffer、filename和文件type
const base64Data = arrayBufferToBase64(arraybuffer);
// 拼接参数并编码特殊字符
const customParams = `filename=${encodeURIComponent(filename)}&type=${encodeURIComponent(type)}&data=${base64Data}`;
// 打开WebResource
Xrm.Utility.openWebResource('Shared/Download', customParams, 300, 300);

Shared/Download.html端(解码并下载):

<!DOCTYPE html>
<html>
<head>
  <script>
    // 获取URL参数的工具函数
    function getQueryParam(name) {
      return new URLSearchParams(window.location.search).get(name);
    }

    window.onload = () => {
      const filename = decodeURIComponent(getQueryParam('filename'));
      const type = decodeURIComponent(getQueryParam('type'));
      const base64Data = getQueryParam('data');

      // Base64解码回Blob
      const byteChars = window.atob(base64Data);
      const byteNumbers = new Array(byteChars.length);
      for (let i = 0; i < byteChars.length; i++) {
        byteNumbers[i] = byteChars.charCodeAt(i);
      }
      const byteArray = new Uint8Array(byteNumbers);
      const blob = new Blob([byteArray], { type });

      // 触发下载
      if (window.navigator.msSaveBlob) {
        window.navigator.msSaveBlob(blob, filename);
      } else {
        const downloadUrl = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = downloadUrl;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(downloadUrl);
      }
      // 下载完成后关闭窗口
      window.close();
    };
  </script>
</head>
<body></body>
</html>

⚠️ 注意:这个方案适合小文件,因为Base64会让文件体积增加约33%,如果文件太大可能会触发URL长度限制。


方案2:直接在WebResource中通过Web API拉取文件(适合大文件)

如果文件比较大,传递Base64不太现实,我们可以换个思路:不在表单脚本里获取文件内容,而是把文件的标识(比如实体ID、字段名)传给WebResource,让WebResource直接调用CRM Web API获取文件Blob,再触发下载。

表单脚本端(传递文件标识):

const recordId = Xrm.Page.data.entity.getId().replace(/[{}]/g, ''); // 去掉ID的大括号
const customParams = `recordId=${recordId}&fieldName=your_file_field_name&filename=${encodeURIComponent('your_file_name.ext')}`;
Xrm.Utility.openWebResource('Shared/Download', customParams, 300, 300);

Shared/Download.html端(调用Web API下载):

<!DOCTYPE html>
<html>
<head>
  <!-- 引入CRM全局上下文,自动处理认证 -->
  <script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>
  <script>
    function getQueryParam(name) {
      return new URLSearchParams(window.location.search).get(name);
    }

    window.onload = () => {
      const recordId = getQueryParam('recordId');
      const fieldName = getQueryParam('fieldName');
      const filename = decodeURIComponent(getQueryParam('filename'));
      const clientUrl = Xrm.Utility.getGlobalContext().getClientUrl();

      // 调用Web API获取文件Blob
      const req = new XMLHttpRequest();
      req.open('GET', `${clientUrl}/api/data/v8.2/your_entity_name(${recordId})/${fieldName}/$value`, true);
      req.responseType = 'blob';
      req.setRequestHeader('OData-MaxVersion', '4.0');
      req.setRequestHeader('OData-Version', '4.0');
      req.setRequestHeader('Accept', 'application/octet-stream');

      req.onload = () => {
        if (req.status === 200) {
          const blob = req.response;
          // 触发下载逻辑和之前一致
          if (window.navigator.msSaveBlob) {
            window.navigator.msSaveBlob(blob, filename);
          } else {
            const downloadUrl = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = downloadUrl;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(downloadUrl);
          }
        }
        window.close();
      };
      req.send();
    };
  </script>
</head>
<body></body>
</html>

这个方案不需要传递大体积数据,完全适配大文件场景,而且利用CRM的Web API自动处理权限,不需要额外认证逻辑。


额外提示:关于CRM沙箱的DOM操作限制

其实CRM 8.2的沙箱并非完全禁止document.createElement,只是对直接操作表单DOM有严格限制。在独立的WebResource页面里,你完全可以正常使用DOM操作来创建a标签触发下载,这也是上面两个方案可行的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:53:58