在 Azure Function 上获取数据时,HttpClient.GetAsync() 会产生 AggregateException

Posted

技术标签:

【中文标题】在 Azure Function 上获取数据时,HttpClient.GetAsync() 会产生 AggregateException【英文标题】:HttpClient.GetAsync() gives an AggregateException while fetching data on Azure Function 【发布时间】:2021-06-01 06:35:48 【问题描述】:

我正在尝试使用 URL 从 Zoho 获取员工数据:

https://people.zoho.com/people/api/forms/P_EmployeeView/records 

使用HttpClientGetAsync()。在我的本地开发环境中执行代码时,代码运行平稳并获取所需的数据,但是一旦我将代码发布到 azure 函数,我就会收到以下堆栈跟踪的异常:

2021-06-01T06:14:45.870 [Error] System.AggregateException: One or more errors occurred. (One or
 more errors occurred. (A connection attempt failed because the connected party did not properly 
respond after a period of time, or established connection failed because connected host has failed 
to respond.))---> System.AggregateException: One or more errors occurred. (A connection attempt 
failed because the connected party did not properly respond after a period of time, or established 
connection failed because connected host has failed to respond.)---> 
System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did 
not properly respond after a period of time, or established connection failed because connected 
host has failed to respond.---> System.Net.Sockets.SocketException (10060): A connection attempt 
failed because the connected party did not properly respond after a period of time, or established 
connection failed because connected host has failed to respond.at 
System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken 
cancellationToken)--- End of inner exception stack trace ---at 
System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken 
cancellationToken)at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request,
 Boolean allowHttp2, CancellationToken cancellationToken)at 
System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, 
CancellationToken cancellationToken)at 
System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, 
CancellationToken cancellationToken)at 
System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean 
doRequestAuth, CancellationToken cancellationToken)at 
System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken 
cancellationToken)at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request,
 CancellationToken cancellationToken)at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 
sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)--- End of 
inner exception stack trace ---at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean 
includeTaskCanceledExceptions)at System.Threading.Tasks.Task`1.GetResultCore(Boolean 
waitCompletionNotification)at System.Threading.Tasks.Task`1.get_Result()at 
EmployeeDataRefresh.ZohoClient.GetEmployeeData(ILogger log) in 
C:\Projects\ZohoAttendance\Internal-Automation-and-Power-BI-Dashboard-zoho-employee-data-
update\src\EmployeeDataRefresh\EmployeeDataRefresh\ZohoClient.cs:line 39--- End of inner exception
 stack trace ---at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean 
includeTaskCanceledExceptions)at System.Threading.Tasks.Task`1.GetResultCore(Boolean 
waitCompletionNotification)at System.Threading.Tasks.Task`1.get_Result()at 
EmployeeDataRefresh.Trigger.DoRefresh(ILogger log) in C:\Projects\ZohoAttendance\Internal-
Automation-and-Power-BI-Dashboard-zoho-employee-data-
update\src\EmployeeDataRefresh\EmployeeDataRefresh\Trigger.cs:line 68at 
EmployeeDataRefresh.Trigger.AutoRefreshEmployeeData(TimerInfo myTimer, ILogger log) in 
C:\Projects\ZohoAttendance\Internal-Automation-and-Power-BI-Dashboard-zoho-employee-data-
update\src\EmployeeDataRefresh\EmployeeDataRefresh\Trigger.cs:line 30

这是我获取数据的代码

using(var httpClient = new HttpClient())

    httpClient.DefaultRequestHeaders.Authorization
             = new AuthenticationHeaderValue("Bearer", _authToken);
    Uri myUri = new Uri(_url, UriKind.Absolute);
    var response = httpClient.GetAsync(myUri);
    log.LogInformation(_authToken);
    log.LogInformation("Sending Get Request to Zoho...\n");
    var data = await response.Result.Content.ReadAsStringAsync();
    log.LogInformation("Data fetched from Zoho...\n");
    var employes = JsonConvert.DeserializeObject<List<Employee>>(data);

    return employes;

我在行得到错误

var data = await response.Result.Content.ReadAsStringAsync();

我已经放置了各种日志语句来调试问题,并且在 azure 函数日志上打印的最后一条日志语句是“向 Zoho 发送获取请求...”。 我已经打印了令牌和其他必需的变量,以检查它们是否具有正确的值并且获得了正确的值,因此无效的令牌绝对不是问题。有人可以提出这个错误的可能原因吗?

【问题讨论】:

zoho服务是否有IP限制? @user1672994 如果有 IP 限制,我将如何从 zoho 本身获取身份验证令牌?但是,如果您这么说,我只会确认一次。 你从哪里得到_authToken? @ShubhamTiwari - 如果您认为没有配置问题,那么您可以提出 Azure 支持票,他们可以针对此出站连接问题提供帮助 【参考方案1】:

你期待 json 响应类型吗?为了获得最佳实践,您可能需要在 httpclient 的标头中提供

string contentTypeValue = "application/json";
client.DefaultRequestHeaders.Add("Content-Type", contentTypeValue);

还要练习

 httpResponse.EnsureSuccessStatusCode(); // throws if not 200-299

在读取结果流之前。

【讨论】:

感谢您告诉我最佳实践,但我确信这些东西不会解决问题,因为我已经尝试过了,我认为是 Zoho API 问题。【参考方案2】:

这里没有token或任何身份验证的问题,只需清除异步编程, 第一, 相反,通过获取response.Result 属性的值,可以强制当前线程等待异步操作完成,其次我会推荐

static readonly HttpClient client = new HttpClient();
    try
    
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _authToken);
        Uri myUri = new Uri(_url, UriKind.Absolute);
        HttpResponseMessage response = await client.GetAsync(_url);
        var data = await response.Result.Content.ReadAsStringAsync();
        var employes = JsonConvert.DeserializeObject<List<Employee>>(data);
    
    catch (Exception)
    

        throw;
    

【讨论】:

所以我想你是在告诉我等待 GetAsync() 然后做一个 response.Content.ReadAsStringAsync().Result;因为您提到的代码不正确,我想是因为 HttpResponseMessage 对象“响应”没有 Result 属性。 @ShubhamTiwari 是的,你是对的,我们必须在 ReadAsStringAsync() 中使用 await;我正在编辑我的答案,但你应该等到所有数据都获取。 我试过了,但它在 azure 函数上仍然有同样的异常,奇怪的是现在 OAuth API 有时也会失败,有时它会给我访问令牌,只有员工数据 API 失败所以我想知道是不是 Zoho API 有问题。 @KartikMaheshwari - 声明 var data = await response.Result.Content.ReadAsStringAsync() 是否需要更改为 var data = await response.Content.ReadAsStringAsync() @user1672994 出现错误,例如“错误 CS1061 'Task' 不包含'Content'的定义,并且没有可访问的扩展方法'Content'接受'Task'(您是否缺少 using 指令或程序集引用?)”。

以上是关于在 Azure Function 上获取数据时,HttpClient.GetAsync() 会产生 AggregateException的主要内容,如果未能解决你的问题,请参考以下文章

使用 Java 从 Azure Function QueueTrigger 获取消息元数据

如何使用 id_token 从 Azure Function 应用程序获取 Azure access_token?

Azure App Function (Functions 2.x):通过 HTTP 函数在 CosmosDB 中创建新文档

Azure Function v3 - 在启动中添加标识时“无法访问 Azure Functions 运行时”

实现 JWT 身份验证 Azure Function 3.x - 使用 JWT 令牌获取当前用户的声明

如何在 Azure Function C# 中获取文件夹的路径