【问题标题】:client.PostAsync hangs despite receiving a response and not incurring a deadlock尽管收到响应并且没有导致死锁,client.PostAsync 仍挂起
【发布时间】:2021-10-19 17:18:21
【问题描述】:

我需要将数据发布到 AWS API 网关,并且我正在使用 client.PostAsync() 来执行此操作。以下是发出请求的方法的代码:

async Task<string> asyncAPI(string route, string password = "", string data = "", string service = "")
{
    HttpClient client = new HttpClient();
    Uri uri = new Uri("api");
    string json = JsonConvert.SerializeObject(new APIrequest(default, route, password, default, service, "dawdasdqwd2"));
    StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
    client.DefaultRequestHeaders.Add("x-api-key", "key");
    HttpResponseMessage response = null;
    response = await client.PostAsync(uri, content);
    return await response.Content.ReadAsStringAsync();
}

调用asyncAPI()的方法的代码是

async Task processImage()
{
    using (WebClient wc = new WebClient())
    {
        byte[] b = System.IO.File.ReadAllBytes(StringPhotoPath);
        string s = Convert.ToBase64String(b);
        string response=await asyncAPI("run_script", "", s, "Image_Processor");
        //more code here not relevant to the question
    }
}  

最后,这里是调用processImage() 的代码。它也是异步的,当在应用程序中按下按钮时调用它(这个项目是 Xamarin.Forms)。

private async void takePhoto(object sender, EventArgs e)
{
    using(var progress = UserDialogs.Instance.Loading("Loading..."))
    {
        await TakePhotoAsync();
        if (PhotoPath != null)
        {
            PhotoImage.Source = PhotoPath;
            if(PhotoGrid ==null)
            {
                PhotoGrid = new AbsoluteLayout() { HeightRequest = PhotoImage.Height, WidthRequest = PhotoImage.Width };
                PhotoMenu.Children.Add(PhotoGrid, Convert.ToInt32(PhotoImage.X), Convert.ToInt32(PhotoImage.Y));
            }
            else
            {
                PhotoGrid.Children.Clear();
            }
            PhotoButton.IsVisible = false;
            PhotoMenu.IsVisible = true;
            await processImage();
        }
    }
}

由于它是一个调用异步方法的异步方法,并且没有使用.ResultConfigureAwait(false),所以我认为异步阻塞不可能发生任何死锁。但是,当我通过 asyncAPI 断点时,代码会挂起并最终在client.PostAsync(...) 上超时

我认为这是 API 的问题,但我打开了 CloudWatch 日志记录,发现 API 工作正常。这是其中一次运行的日志:

(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Extended Request Id: EOaW6FP2iYcF8Ww=
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Verifying Usage Plan for request: 70c0f6d0-d89f-4714-9fc2-d44979c886b7. API Key: **********************************TLcZh0 API Stage: uidvxrcio9/default
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Usage Plan check succeeded for API Key **********************************TLcZh0 and API Stage uidvxrcio9/default
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Starting execution for request: 70c0f6d0-d89f-4714-9fc2-d44979c886b7
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) HTTP Method: POST, Resource Path: /Blueline_General_API
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) API Key: **********************************TLcZh0
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) API Key ID: 5evbipy70k
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Method request path: {}
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Method request query string: {}
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Method request headers: {x-api-key=**********************************TLcZh0, X-Forwarded-Proto=https, X-Forwarded-For=172.58.174.185, Host=uidvxrcio9.execute-api.us-east-2.amazonaws.com, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=1-611c0a92-3f8e5be1229e0ccb2d549848, Content-Type=application/json}
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Method request body before transformations: {
    "command": null,
    "route": "password_confirm",
    "password": "chiefwindfractionlie",
    "sqlctype": null,
    "service": "",
    "data": ""
}
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Endpoint request URI: https://lambda.us-east-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-2:821930216915:function:Blueline_General_API/invocations
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Endpoint request headers: {x-amzn-lambda-integration-tag=70c0f6d0-d89f-4714-9fc2-d44979c886b7, Authorization=************************************************************************************************************************************************************************************************************************************************************************************************************************601604, X-Amz-Date=20210817T191426Z, x-amzn-apigateway-api-id=uidvxrcio9, X-Amz-Source-Arn=arn:aws:execute-api:us-east-2:821930216915:uidvxrcio9/default/ANY/Blueline_General_API, Accept=application/json, User-Agent=AmazonAPIGateway_uidvxrcio9, X-Amz-Security-Token=IQoJb3JpZ2luX2VjEFIaCXVzLWVhc3QtMiJIMEYCIQCv7g3zqjGQXaVMoAAuvAFuzwA5T4KClHwsCZ9B7sjmOgIhALAdux0OPaSQA5Uzki/BH50sOlNiOyh20Toe+6in4qcnKvoDCHsQAhoMNzE4NzcwNDUzMTk1IgyDrpWGGaECTHAmm/oq1wOkgn4rG/303C6njgV3/40y8A6paYVJoV/GFcKQCnKnhR/clpiVIfVmcI0WxUANd1lrOQ/jNuSVyA9yWgjv7Lk+VQRJ1Ae4cw+MmK3Ps7cPBMA6MPB/V0pFCDUFI+fMnwWKqukdzXY/HR+CFLSDdmUQpoW546 [TRUNCATED]
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Endpoint request body after transformations: {"resource":"/Blueline_General_API","path":"/Blueline_General_API","httpMethod":"POST","headers":{"Content-Type":"application/json","Host":"uidvxrcio9.execute-api.us-east-2.amazonaws.com","X-Amzn-Trace-Id":"Root=1-611c0a92-3f8e5be1229e0ccb2d549848","x-api-key":"slq0NuO8XaubhaMS8QY98akA5h643F7rTRTLcZh0","X-Forwarded-For":"172.58.174.185","X-Forwarded-Port":"443","X-Forwarded-Proto":"https"},"multiValueHeaders":{"Content-Type":["application/json"],"Host":["uidvxrcio9.execute-api.us-east-2.amazonaws.com"],"X-Amzn-Trace-Id":["Root=1-611c0a92-3f8e5be1229e0ccb2d549848"],"x-api-key":["slq0NuO8XaubhaMS8QY98akA5h643F7rTRTLcZh0"],"X-Forwarded-For":["172.58.174.185"],"X-Forwarded-Port":["443"],"X-Forwarded-Proto":["https"]},"queryStringParameters":null,"multiValueQueryStringParameters":null,"pathParameters":null,"stageVariables":null,"requestContext":{"resourceId":"vnime3","resourcePath":"/Blueline_General_API","httpMethod":"POST","extendedRequestId":"EOaW6FP2iYcF8Ww=","reque [TRUNCATED]
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Sending request to https://lambda.us-east-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-2:821930216915:function:Blueline_General_API/invocations
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Received response. Status: 200, Integration latency: 827 ms
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Endpoint response headers: {Date=Tue, 17 Aug 2021 19:14:27 GMT, Content-Type=application/json, Content-Length=136, Connection=keep-alive, x-amzn-RequestId=4052aff4-fbe6-4e48-b693-d8f41280c722, x-amzn-Remapped-Content-Length=0, X-Amz-Executed-Version=$LATEST, X-Amzn-Trace-Id=root=1-611c0a92-3f8e5be1229e0ccb2d549848;parent=7ff28da0447ec7fe;sampled=1}
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Endpoint response body before transformations: {
    "isBase64Encoded": false,
    "statusCode": 200,
    "headers": {
        "Access-Control-Allow-Origin": "*"
    },
    "multiValueHeaders": {},
    "body": "\"T\""
}
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Method response body after transformations: "T"
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Method response headers: {Access-Control-Allow-Origin=*, X-Amzn-Trace-Id=Root=1-611c0a92-3f8e5be1229e0ccb2d549848}
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Successfully completed execution
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) Method completed with status: 200
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) AWS Integration Endpoint RequestId : 4052aff4-fbe6-4e48-b693-d8f41280c722
(70c0f6d0-d89f-4714-9fc2-d44979c886b7) X-ray Tracing ID : Root=1-611c0a92-3f8e5be1229e0ccb2d549848

这正是我想要的; Lambda 函数返回的响应是正确的。

为什么尽管有正确的异步代码和正确的 API 响应,client.PostAsync(...) 仍会挂起,我该如何解决?

【问题讨论】:

  • 可以添加调用processImage()的代码吗?
  • 好吧,我刚刚做了;它也是异步的,所以我认为这不是问题
  • 每次调用都会打开一个新的 HttpClient 实例,这可能会导致端口耗尽并阻止响应到达您的应用程序。您是否尝试过使用单个静态 HttpClient 实例并查看行为是否已解决?
  • 我想过这个,但没有任何情况下它可以工作。甚至调用此方法的第一个实例也会挂起。
  • 无论如何我都试过了,结果一样

标签: c# json amazon-web-services aws-lambda


【解决方案1】:

Stephen Cleary 的建议是正确的,可能还有其他原因使 UI 线程处于忙碌状态;这是takePhoto()中的using语句

修改后的工作代码如下:

private async void takePhoto(object sender, EventArgs e)
{
    await TakePhotoAsync();
    if (PhotoPath != null)
    {
        PhotoImage.Source = PhotoPath;
        if(PhotoGrid ==null)
        {
            PhotoGrid = new AbsoluteLayout() { HeightRequest = PhotoImage.Height, WidthRequest = PhotoImage.Width };
            PhotoMenu.Children.Add(PhotoGrid, Convert.ToInt32(PhotoImage.X), Convert.ToInt32(PhotoImage.Y));
        }
        else
        {
            PhotoGrid.Children.Clear();
        }
        PhotoButton.IsVisible = false;
        PhotoMenu.IsVisible = true;
        await processImage();
    }
}

删除此 using 语句会解除对 UI 线程的阻塞,并允许应用接收已完成的任务并继续执行。

【讨论】:

    猜你喜欢
    • 2016-02-22
    • 1970-01-01
    • 2013-01-28
    • 2017-10-20
    • 2015-10-23
    • 1970-01-01
    • 2015-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多