Office Script使用Fetch请求OAuth2 Token返回Failed to Fetch问题排查
Office Script 实现OAuth密码模式获取令牌失败的解决思路
问题背景
尝试用Office Script编写获取OAuth API令牌的函数,已有可正常运行的PowerShell示例,但使用fetch实现时返回“failed to fetch”错误。
可正常运行的PowerShell代码
#requires -Version 3.0 function New-ApiAccessToken { param ( [string]$apiUrl, [string]$apiKey, [string]$apiSecretKey ) # Specify security protocols [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12' # Convert password to secure string $securePassword = ConvertTo-SecureString -String 'public' -AsPlainText -Force # Define parameters for Invoke-WebRequest cmdlet $params = @{ Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ('public-client', $securePassword) Uri = '{0}/auth/oauth/token' -f $apiUrl Method = 'POST' ContentType = 'application/x-www-form-urlencoded' Body = 'grant_type=password&username={0}&password={1}' -f $apiKey, $apiSecretKey } # Request access token try {(Invoke-WebRequest @params | ConvertFrom-Json).access_token} catch {$_.Exception} } # Define parameters $params = @{ apiUrl = 'myurlhere' apiKey = 'thekey' apiSecretKey = 'thesecretkey' } # Call New-ApiAccessToken function using defined parameters New-ApiAccessToken @params
报错的Office Script代码
async function getToken() { let url = 'myurlhere'; let client_id = 'public-client'; let client_secret = 'public'; let username = 'thekey'; let password = 'thesecretkey'; let basicAuth: string = base64Encode(client_id + ":" + client_secret).toString(); let bodyParams: URLSearchParams = new URLSearchParams(); bodyParams['grant_type'] = 'password'; bodyParams['username'] = username; bodyParams['password'] = password; let response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json; charset=UTF-8', 'Authorization': 'Basic ' + basicAuth }, body: bodyParams }); let token: string = await response.json(); console.log(token) }
抓包对比结果
- PowerShell脚本发起2次POST请求:第一次返回401,第二次获取令牌返回200
- Office Script仅发起1次OPTIONS请求,返回401,无后续请求
解决方案
1. 修正请求URL
PowerShell中拼接了完整的令牌端点路径{0}/auth/oauth/token,但Office Script里的url仅写了基础地址myurlhere,缺少后续路径,导致请求地址错误,需补充完整路径。
2. 处理CORS预检OPTIONS 401问题
Office Script运行在浏览器环境,跨域请求会先发送OPTIONS预检请求。若API服务器未配置允许OPTIONS请求通过,会直接返回401,阻断后续POST请求。需联系API管理员配置CORS规则:
- 允许Office Script的请求Origin(或临时设为
*测试) - 允许
Content-Type、Authorization等请求头 - 允许
POST方法 - 配置OPTIONS请求跳过认证校验
3. 确保Basic Auth编码正确
Office Script中的自定义base64Encode可能存在实现问题,改用浏览器原生的btoa()函数完成Base64编码:
let basicAuth: string = btoa(`${client_id}:${client_secret}`);
注意:btoa仅支持ASCII字符,若包含特殊字符需先转码。
4. 调整请求体构造方式
直接用字符串拼接请求体,确保格式与PowerShell完全一致,避免URLSearchParams可能带来的格式差异:
let body = `grant_type=password&username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`;
5. 完整修正后的Office Script代码
async function getToken() { let baseUrl = 'myurlhere'; // 补充完整的令牌端点路径 let url = `${baseUrl}/auth/oauth/token`; let client_id = 'public-client'; let client_secret = 'public'; let username = 'thekey'; let password = 'thesecretkey'; // 使用浏览器原生btoa进行Base64编码 let basicAuth: string = btoa(`${client_id}:${client_secret}`); // 手动构造符合要求的请求体字符串 let body = `grant_type=password&username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`; try { let response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json; charset=UTF-8', 'Authorization': `Basic ${basicAuth}` }, body: body }); if (!response.ok) { // 打印详细错误信息便于排查 const errorText = await response.text(); console.error(`请求失败,状态码:${response.status},响应内容:${errorText}`); return; } let tokenData = await response.json(); console.log(`获取到的令牌:${tokenData.access_token}`); return tokenData.access_token; } catch (error) { console.error(`请求异常:${error}`); } }
关键说明
跨域预检OPTIONS 401是核心问题,若无法修改API服务器的CORS配置,Office Script的跨域请求将无法完成。同时需确保请求地址、请求体格式、Basic Auth编码完全匹配PowerShell的成功请求,减少格式差异导致的错误。
内容的提问来源于stack exchange,提问作者Amy
相关产品推荐
相关产品推荐

