【问题标题】:co_await HttpClient::PutAsync never completes (using c++, coroutine, UWP)co_await HttpClient::PutAsync 永远不会完成(使用 c++、协程、UWP)
【发布时间】:2017-11-22 11:11:38
【问题描述】:

我做 http 请求,当它们失败时我重复请求。我通过拔下互联网电缆到我的计算机并重新插入来模拟它。我的代码大部分时间都可以工作,但有时

co_await HttpClient::PutAsync() 永远不会“返回”或完成。

我的代码如下所示:

task<Aws::Result> Aws::S3Request::tryExecute()
{
    // content
    IHttpContent^ httpContent;
    httpContent = ref new HttpBufferContent(mBufferContent);
    httpContent->Headers->ContentType = ref new Headers::HttpMediaTypeHeaderValue(ref new String(mContentType.c_str()));

    std::wstring signature = getSignature();

    // client
    auto filter = ref new ::Filters::HttpBaseProtocolFilter;
    filter->AllowUI = false;
    filter->CacheControl->ReadBehavior = Filters::HttpCacheReadBehavior::NoCache;
    filter->CacheControl->WriteBehavior = Filters::HttpCacheWriteBehavior::NoCache;
    HttpClient^ httpClient = ref new HttpClient(filter);
    httpClient->DefaultRequestHeaders->Authorization = ref new Headers::HttpCredentialsHeaderValue(L"AWS", ref new String((mUser.mAccessKey + L":" + signature).c_str()));
    httpClient->DefaultRequestHeaders->Append(L"Date", ref new String(mDate.c_str()));
    httpClient->DefaultRequestHeaders->Append(L"x-amz-acl", L"public-read");
    httpClient->DefaultRequestHeaders->Append(L"x-amz-security-token", ref new String(mUser.mSessionToken.c_str()));

    // http req
    Uri^ uri = ref new Uri(ref new String(mUri.c_str()));
    HttpResponseMessage^ response;
    IAsyncOperationWithProgress<HttpResponseMessage^, HttpProgress>^ progress;
    try
    {
        progress = httpClient->PutAsync(uri, httpContent);
        progress->Progress = ref new AsyncOperationProgressHandler<HttpResponseMessage^, HttpProgress>(
            [this](IAsyncOperationWithProgress<HttpResponseMessage^, HttpProgress>^ pretask, HttpProgress progressInfo)
        {
            /*double got = progressInfo.BytesReceived + progressInfo.BytesSent;
            double total = 0;
            if (progressInfo.TotalBytesToReceive)
            total += progressInfo.TotalBytesToReceive->Value;
            if (progressInfo.TotalBytesToSend)
            total += progressInfo.TotalBytesToSend->Value;
            float progress = (total >= 1) ? float(got / total) : 0.0f;
            debugOut("--- part progress = ", progress);
            if (mProgress)
            *mProgress = progress;*/
        }
        );
        response = co_await progress;
        progress = nullptr;
        if (!response->IsSuccessStatusCode)
            debugOut("--- http fail error");
    }
    catch (Platform::COMException^)
    {
        debugOut("--- http fail nointernet");
        progress = nullptr;
        mResult = NoInternet;
        mAnswer.clear();
        co_return mResult;
    }

    // answer
    mAnswer = response->Content->ToString()->Data();
    debugOut(L"--- Http answer=", mAnswer);
    mResult = response->IsSuccessStatusCode ? Success : Error;

    co_return mResult;
}

如果失败,则再次调用 tryExecute()。

顺便说一句,IAsyncOperationWithProgress 只给我 0% 或 100%,而不是中间值。我在每个请求中上传大小为 5 MB。

【问题讨论】:

  • “我的代码大部分时间都有效,但有时”,所以这不是 100% 重现的问题吗?失败的时候有什么特别的吗?服务端对put请求有什么限制吗?
  • 可能有 10% 的时间我拔掉电缆并重新插入,co_await PutAsync 永远不会“返回”或完成。就像缺少超时一样。

标签: c++ uwp coroutine


【解决方案1】:

这可行,但不是一个好的解决方案:

//response = co_await progress;
for (int timeout = 5*60*100; true; timeout--)
{
    if (progress->Status != AsyncStatus::Started)
        break;
    co_await winrt::resume_after(10ms);
    if (timeout == 0)
    {
        debugOut("--- http fail timeout");
        mResult = NoInternet;
        mAnswer.clear();
        co_return mResult;
    }
}
response = progress->GetResults();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    • 2017-01-27
    相关资源
    最近更新 更多