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

Mac Safari/Mac Outlook中JavaScript Async/Await参数异常求助

解决Safari中Office插件异步函数传参丢失及AES-CBC兼容性问题

核心症状

  • Mac Outlook插件通过displayDialogAsync加载的对话框空白,重构后Chrome/Edge/Firefox运行正常,但Safari中异步函数传入的任意参数均为undefined
  • 网页版outlook.office365.com的Safari环境下,Office.context.mailbox.item.getBodyAsync()等所有Office API异步调用报错,将变量复制到全局空间后可正常运行
  • Safari中AES-CBC加密生成的PIN值,与其他浏览器及后端PHP不兼容
  • 表单提交时,输入框值传递到异步函数失败,临时方案为:通过构造函数/同步getter/setter预存参数,再调用无参数的async/await函数,所有环境恢复正常

解决方案

1. 修复异步函数传参丢失问题

(1)规避嵌套异步闭包的作用域差异

Safari对嵌套异步函数的闭包处理存在特殊性,可将需要传递的参数提前绑定到全局/模块级作用域,避免在异步回调中直接传参:

let globalParentData;
window.addEventListener("onload", () => {
  // 同步解析参数,脱离异步闭包
  globalParentData = JSON.parse(window.atob(decodeURIComponent(o_q_s_data)));
  
  Office.onReady(async () => {
    await buildForm(null, globalParentData);
  });
});
(2)调整函数声明方式

赋值式声明的异步函数(buildForm = async (...) => {})在Safari中可能存在作用域提升问题,改为函数声明式:

async function buildForm(t, parentData) {
  const data = JSON.parse(parentData.data);
  // ...业务逻辑
}
(3)显式绑定上下文

用bind强制传递参数上下文,避免Safari的闭包参数丢失:

Office.onReady(async () => {
  const parentData = JSON.parse(window.atob(decodeURIComponent(o_q_s_data)));
  await buildForm.bind(null, null, parentData)();
});

2. 解决AES-CBC加密兼容性问题

(1)统一Web Crypto API的加密参数

Safari对AES-CBC的IV长度、密钥格式要求更严格,需确保:

  • IV长度严格为16字节(AES块大小),不足时用PKCS#7填充
  • 密钥导入时明确指定extractable和keyUsages参数:
async function encryptWithAES(data, keyStr) {
  const encoder = new TextEncoder();
  const iv = crypto.getRandomValues(new Uint8Array(16)); // 固定16字节IV
  
  // 标准化密钥导入
  const cryptoKey = await crypto.subtle.importKey(
    "raw",
    encoder.encode(keyStr),
    { name: "AES-CBC" },
    true,
    ["encrypt"]
  );
  
  const encryptedBuffer = await crypto.subtle.encrypt(
    { name: "AES-CBC", iv: iv },
    cryptoKey,
    encoder.encode(data)
  );
  
  // 统一编码格式,与后端对齐
  return {
    iv: btoa(String.fromCharCode(...iv)),
    encryptedData: btoa(String.fromCharCode(...new Uint8Array(encryptedBuffer)))
  };
}
(2)与后端PHP统一填充规则

PHP默认用零填充,而Web Crypto用PKCS#7填充,需两端统一:

  • 前端加密前手动做PKCS#7填充
  • 后端改用openssl_encrypt并指定PKCS#7填充,示例:
$encrypted = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
// 前端解密时对应处理

3. 修复Office API异步调用报错问题

(1)确保Office API完全初始化

Safari中Office API的初始化可能存在延迟,需在Office.onReady中验证核心对象存在后再调用:

Office.onReady(async () => {
  const checkMailboxReady = () => {
    if (Office.context.mailbox?.item) {
      // 执行getBodyAsync等操作
      Office.context.mailbox.item.getBodyAsync("html", (result) => {
        if (result.status === Office.AsyncResultStatus.Succeeded) {
          // 处理结果
        }
      });
    } else {
      setTimeout(checkMailboxReady, 100); // 重试
    }
  };
  checkMailboxReady();
});
(2)封装Office API为Promise

部分Office API不原生支持Promise,手动封装后可避免回调嵌套问题:

function getBodyAsyncPromise(format = "html") {
  return new Promise((resolve, reject) => {
    Office.context.mailbox.item.getBodyAsync(format, (result) => {
      result.status === Office.AsyncResultStatus.Succeeded 
        ? resolve(result.value) 
        : reject(result.error);
    });
  });
}

// 调用示例
Office.onReady(async () => {
  const body = await getBodyAsyncPromise();
  // ...后续逻辑
});

内容的提问来源于stack exchange,提问作者David E. Craig

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 08:03:12