Docker容器中用HttpClient调用Microsoft Graph超时100秒,但curl可正常访问
问题:树莓派Docker容器中.NET 6调用Microsoft Graph超时,curl正常
我在树莓派的Docker容器中运行.NET 6/ASP.NET Core应用,通过Microsoft Graph SDK访问Outlook和OneDrive。7月29日周五,未改动运行环境的情况下应用突然无法正常工作,推测可能是Azure Active Directory或Graph的令牌行为等发生变更。
我剥离了应用中的Graph相关层排查问题:在容器内使用以下HttpClient代码调用Graph接口时,即使设置了Timeout.InfiniteTimeSpan,仍会在100秒后超时:
var client = new HttpClient(); client.Timeout = Timeout.InfiniteTimeSpan; client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.AccessToken); client.BaseAddress = new Uri("https://graph.microsoft.com"); var response = await client.GetAsync("v1.0/me"); var result = await response.Content.ReadAsStringAsync(); return Ok(new HealthResult { Result = result });
超时错误信息如下:
2022-07-31T07:46:21.622984734Z fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1] 2022-07-31T07:46:21.623189265Z An unhandled exception has occurred while executing the request. 2022-07-31T07:46:21.623227911Z System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing. 2022-07-31T07:46:21.623305047Z ---> System.TimeoutException: A task was canceled. 2022-07-31T07:46:21.623336974Z ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
但使用相同的访问令牌,通过以下调用curl的代码调用同一接口却能正常获取响应:
var process = new System.Diagnostics.Process(); process.StartInfo.FileName = "curl"; process.StartInfo.Arguments = $"-H \"Authorization: Bearer {token.AccessToken}\" https://graph.microsoft.com/v1.0/me"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.Start(); string consoleResult = process.StandardOutput.ReadToEnd(); return Ok(new HealthResult { Result = consoleResult });
正常响应示例:
{"result":"{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#users/$entity\",\"displayName\":\"John Doe\",\"surname\":\"Doe\",\"givenName\":\"John\",\"id\":\"1234567890abcdef\",\"userPrincipalName\":\"john.doe@outlook.com\",\"businessPhones\":[],\"jobTitle\":null,\"mail\":null,\"mobilePhone\":null,\"officeLocation\":null,\"preferredLanguage\":null}"}
已尝试的排查操作:
- 在GitHub Codespaces的devcontainer中运行应用,无异常;
- 不带令牌调用Graph,仍出现curl正常、HttpClient超时的情况;
- 设置
Timeout.InfiniteTimeSpan后,需等待7-8分钟才能得到正确结果。
排查思路
检查Docker容器网络配置
- 验证容器DNS解析是否正常,对比curl与HttpClient的DNS结果(可在容器内执行
nslookup graph.microsoft.com测试); - 检查容器网络模式(如bridge/host)是否存在隐性变更,尝试切换网络模式复现测试;
- 确认容器代理设置,curl可能默认继承系统代理,而HttpClient需显式配置。
- 验证容器DNS解析是否正常,对比curl与HttpClient的DNS结果(可在容器内执行
排查.NET HttpClient底层行为差异
- 强制HttpClient使用HTTP/1.1,禁用HTTP/2支持(ARM架构下.NET的HTTP/2实现可能存在兼容性问题):
var handler = new SocketsHttpHandler { UseHttp2 = false }; var client = new HttpClient(handler); - 避免每次请求创建新HttpClient实例,复用实例排查连接池耗尽问题;
- 添加请求头
Connection: Close,禁用HTTP持久连接测试。
- 强制HttpClient使用HTTP/1.1,禁用HTTP/2支持(ARM架构下.NET的HTTP/2实现可能存在兼容性问题):
验证系统级网络差异
- 在树莓派宿主机直接运行.NET应用,排除Docker容器的隔离影响;
- 对比容器内curl命令与.NET调用curl的网络日志,确认请求参数完全一致;
- 检查树莓派系统时间同步状态,虽然curl正常,但令牌验证对时间敏感仍需确认。
抓包分析网络交互细节
- 在容器内用tcpdump或Wireshark捕获HttpClient与curl的请求数据包,对比TCP握手、请求头、响应流程的差异;
- 查看是否存在数据包丢失、握手超时或服务端响应异常的情况。
内容的提问来源于stack exchange,提问作者Kai Walter
相关产品推荐
相关产品推荐

