将Excel VBA的WinHttpRequest令牌获取代码迁移至Office Scripts的Fetch API时遭遇Failed to fetch错误
将Excel VBA的WinHttpRequest令牌获取代码迁移至Office Scripts的Fetch API时遭遇Failed to fetch错误
问题分析
从你的代码对比来看,VBA版本能正常工作是因为它正确处理了请求体编码、请求头和URL,但Office Scripts版本存在几个关键错误,导致了Failed to fetch异常:
关键错误点与修复方案
1. URL和请求体的取值错误
- 你用
Dsheet.getRange("TokenURL").getValue()得到的是string[]类型,但单个单元格的getValue()应该返回string,直接用数组作为fetch的URL会导致请求地址无效。 - 同样,
URLPW = Dsheet.getRange("BBody").getValues()返回的是二维数组,而不是字符串,后续的编码逻辑完全错误。
修复: 单个单元格用getValue()(返回单个值),而非getValues()(返回二维数组)。
2. 请求体的编码与格式错误
VBA里用ADODB.Stream把UTF-8文本转成带BOM的二进制,但Office Scripts里你手动拼接BOM数组的方式不对,而且fetch的body不能直接传普通数字数组,需要传Uint8Array或者符合application/x-www-form-urlencoded格式的内容。
另外,application/x-www-form-urlencoded格式的请求体,其实不需要手动转二进制,直接传编码后的字符串即可,浏览器会自动处理编码(如果是UTF-8的话)。
3. 错误的请求头设置
你添加了"Access-Control-Allow-Origin": "*"请求头,这个头是服务器用来返回给客户端的,不是客户端发送给服务器的。客户端发送这个头不仅无效,还可能干扰正常的请求处理,应该移除。
修正后的Office Scripts代码
async function main(workbook: ExcelScript.Workbook) { const setupSheet = workbook.getWorksheet("Setup"); // 1. 正确获取单个单元格的值(非数组) const tokenUrl = setupSheet.getRange("TokenURL").getValue() as string; const bodyText = setupSheet.getRange("BBody").getValue() as string; try { // 2. 处理请求体:还原VBA里的UTF-8 BOM + 文本二进制逻辑 const encoder = new TextEncoder(); const bom = new Uint8Array([239, 187, 191]); // UTF-8 BOM const bodyBytes = encoder.encode(bodyText); // 拼接BOM和正文二进制 const fullBody = new Uint8Array(bom.length + bodyBytes.length); fullBody.set(bom, 0); fullBody.set(bodyBytes, bom.length); // 3. 发送请求:移除错误的CORS头,对齐VBA的请求头设置 const response = await fetch(tokenUrl, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json" }, body: fullBody }); console.log("Response Status:", response.status); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status} - ${response.statusText}`); } // 4. 正确解析JSON响应(替代VBA里的字符串截取,更可靠) const jsonResponse = await response.json(); // 假设响应格式为 {"token": "your-token-value"},根据实际结构调整属性名 const token = jsonResponse.token; setupSheet.getRange("Token").setValue(token); } catch (error) { console.error("Error retrieving token:", error); // 弹窗提示错误(适配Office Scripts的通知机制) await workbook.getApplication().displayAlert( "Token获取失败", `错误信息: ${error instanceof Error ? error.message : String(error)}`, ExcelScript.AlertType.error ); } }
额外注意事项
关于CORS错误
如果修复后仍然出现Failed to fetch,大概率是CORS跨域限制:
- Office Scripts运行在浏览器环境中,遵循浏览器的CORS政策。如果目标API的服务器没有配置允许Excel Online的域名跨域请求,浏览器会拦截请求。
- 这种情况下,你需要联系API提供方,让他们在服务器响应头中添加
Access-Control-Allow-Origin: https://office.live.com(生产环境不建议用通配符*)。 - 或者,你可以搭建一个后端中转服务,让中转服务调用目标API,再由Office Scripts请求你的中转服务,绕过跨域限制。
关于JSON解析
VBA里用字符串截取的方式提取Token很容易因为响应格式变化失效,Office Scripts里直接解析JSON后通过属性访问会更稳定。如果不确定响应结构,可以先在console.log(jsonResponse)里查看完整响应内容,再调整提取逻辑。




