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

VPN环境下Node.js用Microsoft Graph Client遇TypeError: fetch failed

VPN环境下调用Microsoft Graph API出现TypeError: fetch failed的排查与解决

问题说明

  • 使用环境:Node.js 20.9,依赖msal-node、@microsoft-graph-client
  • 异常现象:
    • VPN外运行代码完全正常
    • VPN内msal-node能成功获取访问令牌,但调用Microsoft Graph API时始终抛出TypeError: fetch failed错误

原代码

const dotenv = require("dotenv");
dotenv.config();
let groupid="";
let driveitemid="";
var msal = require('@azure/msal-node');
MicrosoftGraph = require("@microsoft/microsoft-graph-client");
 const HttpsProxyAgent = require('https-proxy-agent');
 const fetch = require('node-fetch-with-proxy');
 const networkClient={
 sendGetRequestAsync:async function (url, options) {
   const response = await fetch(url, options);
   const json = await response.json();
   const headers = response.headers.raw();
   return {
     headers: Object.create(Object.prototype, headers),
     body: json,
     status: response.status
   }
 }, 
 sendPostRequestAsync:async function (url, options) {
   const sendingOptions = options || {};
   sendingOptions.method = 'post';
   const response = await fetch(url, sendingOptions);
   const json = await response.json()
   const headers = response.headers.raw();
   return {
     headers: Object.create(Object.prototype, headers),
     body: json,
     status: response.status,
     agent:sendingOptions.agent
   }
 
 }}
const agent = new HttpsProxyAgent.HttpsProxyAgent(process.env.http_proxy);
 //require("isomorphic-fetch");

const config = require(`./config/AAD.json`);
async function getClientCredentialsToken(cca) {
    
    const clientCredentialRequest = {
        scopes: ["https://graph.microsoft.com/.default"],     
        skipCache: true,
    };
 return   await  cca
        .acquireTokenByClientCredential(clientCredentialRequest)
        .then((response) => {
          
            console.log("Response: ", response);
            return response;
        
        }).catch((error) => {
           
             console.log(error);
        });
}
async function callGraph(accessToken)
{  
    console.log(agent);
    var client =await MicrosoftGraph.Client.init({     
       debugLogging: false,    
       authProvider: function(authDone) {
         authDone(null, accessToken);
       },
       fetchOptions: {
        //agent: prxyagent
      },
     });

let url=`https://graph.microsoft.com/v1.0/groups/${groupid}/drive/items/${driveitemid}?$expand=thumbnails`
try {
result=await client.api(url).get();
console.log(result);
} catch (error) {
console.log(error);
}
}
let main=async()=>{
       const clientConfig = {
        auth: config.authOptions,
        system: {
           networkClient: networkClient          
            }       
    };
    const confidentialClientApplication = new msal.ConfidentialClientApplication(clientConfig);
 let tokenresponse=await  getClientCredentialsToken(confidentialClientApplication);
   if(tokenresponse.accessToken)
   {
    callGraph(tokenresponse.accessToken);
   }
};
main();

报错信息

TypeError: fetch failed     at Object.fetch (node:internal/deps/undici/undici:11372:11)     at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {   statusCode: -1,   code: 'TypeError',

原因分析

问题出在代理配置的覆盖范围:

  • msal-node通过自定义networkClient使用了带代理支持的node-fetch-with-proxy,所以能正常穿透VPN获取令牌
  • 但@microsoft-graph-client初始化时没有配置代理,默认使用Node.js 20内置的undici fetch,该请求未走VPN代理,导致连接失败

解决方法

修改callGraph函数中Graph Client的初始化配置,将代理agent传入fetchOptions,同时指定使用带代理支持的fetch工具:

async function callGraph(accessToken)
{  
    console.log(agent);
    var client = await MicrosoftGraph.Client.init({     
       debugLogging: false,    
       authProvider: function(authDone) {
         authDone(null, accessToken);
       },
       fetchOptions: {
        agent: agent // 启用代理配置
      },
      fetch: fetch // 指定使用带代理支持的node-fetch-with-proxy
     });

let url=`https://graph.microsoft.com/v1.0/groups/${groupid}/drive/items/${driveitemid}?$expand=thumbnails`
try {
result=await client.api(url).get();
console.log(result);
} catch (error) {
console.log(error);
}
}

额外检查项

  • 确认process.env.http_proxy环境变量已正确设置为VPN代理地址(格式如http://proxy-host:port)
  • 若代理需要认证,可在代理地址中加入用户名密码:http://username:password@proxy-host:port

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:45:40