取消一个“HttpClient”POST请求

5

我正在我的Windows Phone 8应用程序中使用HttpClient.PostAsync()上传图像。用户可以通过UI按钮选择取消此上传。

为了取消POST请求,我设置了一个CancellationToken。但这并不起作用。在取消请求后,我仍然可以在我的代理中看到上传正在进行,很明显该请求被忽略了。我的代码:

using (var content = new MultipartFormDataContent())
{
    var file = new StreamContent(stream);
    file .Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
    {
        FileName =  "filename.jpg",
    };
    file.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
    content.Add(file);

    await httpclient.PostAsync(new Uri("myurl", UriKind.Absolute), content,
        cancellationToken);
}

请注意,我有一个CancellationTokenSource用于CancellationToken。用户单击取消按钮后,将调用tokensource.Cancel()。此外,我的测试用例中的图像大小在1到2 MB之间(并不是很大)。
那么,是否有一种方法可以取消HttpClient的POST请求?

根据这个答案“不能保证取消CancelationTokenSource将取消底层操作。这取决于底层操作的实现(在本例中为SendAsync方法)。操作可能会立即被取消,也可能在几秒钟后或永远不会被取消。” 因此,在进行PostAsync()请求后,您可能需要检查cancellationToken.IsCancellationRequested,如果为真,则调用DeleteAsync()删除已上传的图像。 - DavidRR
虽然您指定了 windows-phone-8,但您并没有指定您是否使用 Windows.Web.Http.HttpClientSystem.Net.Http.HttpClient。(根据传递给 PostAsync() 调用的参数,它似乎是后者。) - DavidRR
3个回答

4
try
{
    var client = new HttpClient();

    var cts = new CancellationTokenSource();
    cts.CancelAfter(3000); // 3 seconds

    var request = new HttpRequestMessage();

    await client.PostAsync(url, content, cts.Token);
}
catch(OperationCanceledException ex)
{
    // timeout has been hit
}

2
你能解释一下为什么这会中止底层操作吗? - Carl in 't Veld

0
在像Xamarin这样的Mono HttpClient实现中,如果主机不可达,则get和post方法不会遵守取消令牌,并且会等待最多2分钟才会失败。这可能是为什么使用CancelAfter的CancellationTokenSource在此处无法工作的原因。
要解决这个问题,我发现最简单的方法是使用Polly库https://github.com/App-vNext/Polly
var policy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(3000),
    TimeoutStrategy.Pessimistic,
    (context, timespan, task) => throw new Exception("Cannot connect to server."));

await policy.ExecuteAsync(async () =>
{
    var httpClient = new HttpClient();
    var response = await httpClient.PostAsync(...);
    response.EnsureSuccessStatusCode();
    ...
});

0
取消任务并不会立即终止它。在执行工作之前,您必须通过检查令牌的状态来手动检查。
if (ct.IsCancellationRequested) 
{
    ct.ThrowIfCancellationRequested();
}

// Post request here...

这篇文章非常有用:如何取消一个任务及其子任务


1
我已经做到了。我的问题是,我想取消已经开始的上传(我在代理中看到上传流量)。尽管我的应用程序停止了工作,并且httpclient响应上的断点也没有触发...但图片已经上传了。 - Joehl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接