Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Polly HandleTransientHttpError没有捕捉到HttpRequestException

Polly HandleTransientHttpError没有捕捉到HttpRequestException
EN

Stack Overflow用户
提问于 2021-10-27 22:20:46
回答 1查看 2.5K关注 0票数 3

我在HttpClient方法中为我的Startup.ConfigureServices创建了一个重试策略。还请注意,默认情况下,asp.net Core2.1为HttpClient发出的每个调用记录4行信息行,这些信息行显示在我问题末尾的日志中。

代码语言:javascript
运行
AI代码解释
复制
services.AddHttpClient("ResilientClient")
            .AddPolicyHandler(
                Policy.WrapAsync(
                    PollyRetryPolicies.TransientErrorRetryPolicy(),
                    Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(60))));

策略定义如下。请注意,我将重试尝试写入日志,因此我将知道是否调用了重试策略。

代码语言:javascript
运行
AI代码解释
复制
public static IAsyncPolicy < HttpResponseMessage > TransientErrorRetryPolicy() {
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .Or < TimeoutRejectedException > ()
        .WaitAndRetryAsync(sleepDurations: ExponentialBackoffPolicy.DecorrelatedJitter(3, SEED_DELAY, MAX_DELAY),
            onRetry: (message, timespan, attempt, context) => {
                context.GetLogger() ? .LogInformation($ "Retrying request to {message?.Result?.RequestMessage?.RequestUri} in {timespan.TotalSeconds} seconds. Retry attempt {attempt}.");
    });
}

HandleTransientHttpError()是一个Polly扩展,它在注释中声明:

配置为处理的条件是:·网络故障(如System.Net.Http.HttpRequestException)

我的httpclient用法如下:

代码语言:javascript
运行
AI代码解释
复制
using (HttpResponseMessage response = await _httpClient.SendAsync(request)) 
{
    response.EnsureSuccessStatusCode();

    try 
    {
        string result = await response.Content.ReadAsStringAsync();
        if (result == null || result.Trim().Length == 0) {
            result = "[]";
        }
        return JArray.Parse(result);
    } catch (Exception ex) {
        _logger.LogInformation($ "Failed to read response from {url}. {ex.GetType()}:{ex.Message}");
        throw new ActivityException($ "Failed to read response from {url}.", ex);
    }
}

捕获了以下日志:

代码语言:javascript
运行
AI代码解释
复制
[Information] System.Net.Http.HttpClient.ResilientClient.LogicalHandler: Start processing HTTP request GET https://api.au.... obfuscated
[Information] System.Net.Http.HttpClient.ResilientClient.CustomClientHandler: Sending HTTP request GET https://api.au..... obfuscated
[Information] System.Net.Http.HttpClient.ResilientClient.CustomClientHandler: Received HTTP response after 2421.8895ms - 200
[Information] System.Net.Http.HttpClient.ResilientClient.LogicalHandler: End processing HTTP request after 2422.1636ms - OK
    
Unknown error responding to request: HttpRequestException:
System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: The server returned an invalid or unrecognized response.

at System.Net.Http.HttpConnection.FillAsync()
at System.Net.Http.HttpConnection.ChunkedEncodingReadStream.CopyToAsyncCore(Stream destination, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.HttpConnectionResponseContent.SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
--- End of inner exception stack trace ---
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at nd_activity_service.Controllers.ActivityController.GetND(String url) in /codebuild/output/src251819872/src/src/nd-activity-service/Controllers/ActivityController.cs:line 561

Http调用成功,我可以看到它返回200-OK。但随后抛出了HttpRequestException。我假设没有调用策略,因为HttpClient消息管道已经解析,因为我们可以看到它返回200-OK。那么,它是如何抛出异常的呢?

我该怎么处理呢?围绕专门处理HttpRequestExceptions的方法包装另一个策略?

这个错误似乎是暂时的。这是一个计划好的作业,下次调用时可以工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-27 23:41:26

您的策略是针对HttpClient而不是针对HttpResponseMessage定义的。

因此,即使您收到例如428,response.EnsureSuccessStatusCode()也将而不是触发器重试。

如果从下游系统接收到408或5XX状态代码,则HandleTransientHttpError将触发重试。当SendAsync抛出HttpRequestException

因为您的异常StackTrace如下所示:

System.Net.Http.HttpRequestException:将内容复制到流中时出错。 System.IO.IOException:服务器返回无效或无法识别的响应。

这就是为什么我的猜测是,这个异常是由HttpContent类抛出的,而您试图读取响应体(ReadAsStringAsync)。

这将不会触发重试,因为您已经在HttpClient上定义了策略。

如果您想在这些情况下进行重试,那么当response.EnsureSuccessStatusCode()抛出HRE或response.Content.ReadAsStringAsync()抛出HRE时,您必须将整个http通信和响应处理逻辑封装到重试策略中。

我来教你怎么做。

首先使用PolicyRegistry而不是AddPolicyHandler

代码语言:javascript
运行
AI代码解释
复制
//services.AddHttpClient("ResilientClient")
//    .AddPolicyHandler(
//        Policy.WrapAsync(
//            TransientErrorRetryPolicy(),
//            Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(60))));

services.AddHttpClient("ResilientClient");
var registry = services.AddPolicyRegistry();
registry.Add("retry", Policy.WrapAsync(
            TransientErrorRetryPolicy(),
            Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(60))));

然后向DI请求注册,例如:

代码语言:javascript
运行
AI代码解释
复制
private readonly IHttpClientFactory factory;
private readonly IReadOnlyPolicyRegistry<string> registry;

public TestController(IHttpClientFactory factory, IReadOnlyPolicyRegistry<string> registry)
{
    this.factory = factory;
    this.registry = registry;
}

最后,检索组合策略并执行http调用:

代码语言:javascript
运行
AI代码解释
复制
var retryPolicy = registry.Get<IAsyncPolicy<HttpResponseMessage>>("retry");
await retryPolicy.ExecuteAsync(async () => await IssueRequest());
代码语言:javascript
运行
AI代码解释
复制
private async Task<HttpResponseMessage> IssueRequest()
{
    var _httpClient = factory.CreateClient("ResilientClient");
    HttpResponseMessage response = await _httpClient.GetAsync("http://httpstat.us/428");

    response.EnsureSuccessStatusCode();
    return response;
}

我使用httpstat.us来模拟428个响应。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69749167

复制
相关文章
在Node.js中读写文件
本文翻译自Reading and Writing Files in Node.js
ccf19881030
2020/10/29
5.3K0
JS动态添加/删除css文件
Jensen_97
2023/07/20
7590
在Node.js中处理Zip文件
Zip 文件是常用的压缩文件格式。在本文中,我将演示如何用 adm-zip npm 模块[1]创建和提取 zip 文件。
疯狂的技术宅
2020/08/10
5.2K0
js中find的用法_js中find函数
首先简单的介绍一下ES6是什么,可能很多人还是第一次听说,我们都知道H5是html的新一代的标准,同样,ES6是javascript的新一代标准,全称是ECMAScript 6.0,简称ES6,其实不是什么神秘的东西。15年6月发布的。
全栈程序员站长
2022/11/04
11.8K0
js中的函数
console.log(fn instanceof Object) // 是Object类型的实例
李才哥
2020/08/17
6.6K0
js中的函数
js中的函数
console.log(fn instanceof Object) // 是Object类型的实例
李才哥
2020/03/28
5.4K0
js中的函数
JS中工厂函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script> //工厂函数是专门创建对象的函数 function createPersion(myname,myage) { let obj=new Object(); obj.name=myname; obj.age=myage; obj.say=functi
贵哥的编程之路
2020/10/28
1.5K0
js中的匿名函数_js匿名函数怎么定义
定义:匿名函数顾名思义指的是没有名字的函数,在实际开发中使用的频率非常高!也是学好JS的重点。
全栈程序员站长
2022/11/10
10.4K0
js函数中使用el表达式传入多个参数时的问题
需求是需要使用js函数执行给某个div标签赋值,但是当传入id和title时就不能进入js中,尝试很久才明白title属于字符串,需要使用引号,但是不确定怎么加,多番调试终于通过了,如下: οnclick="delete1({news.id},{news.title}’);return true;"
geekfly
2022/05/06
2K0
用函数式编程在 JS 中开发游戏
一段时间以来,函数式编程范式比较火热,并且在互联网上有很多关于它的精彩书籍和文章,但是要找到相关程序的真实示例并不容易。因此,我决定尝试使用 Javascript(当今最流行的编程语言)并遵循其概念创建一款游戏。在本文中,我将分享一些经验,并告诉你是否值得。
疯狂的技术宅
2020/03/13
2.2K0
在Node.js中如何逐行读取文件
本文翻译自How to read a file line by line in Node.js
ccf19881030
2020/10/29
13.8K0
js 复制粘贴文章时添加版权信息
<script>        function setClipboardText(event){         event.preventDefault();         var node = document.createElement('div');               node.appendChild(window.getSelection().getRangeAt(0).cloneContents());                var htmlData = '<div>'  
Savalone
2020/02/11
1.3K0
JS中递归函数 18
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <bo
贵哥的编程之路
2020/10/28
2.1K0
html js 数组添加,js数组添加数据
我们在学习python的过程中,会对列表、字符串添加数据。在Javascript中,我们也会对数组添加数据。在不同的位置添加数据有着不同的方法。本文介绍js数组添加数据的三种方法:1、结尾添加push()方法;2、头部添加unshift() 方法;3、向/从数组指定位置添加/删除项目,然后返回被删除的项目splice() 方法。
全栈程序员站长
2022/07/01
26.5K0
JS中的运动函数
分享一个JS封装的运动函数,里面分为弹性运动和缓冲运动两个方法,通过调用startMove()函数来实现动画效果。
越陌度阡
2020/11/26
2.4K0
JS中的高阶函数
在js的内置对象中同样存在着一些高阶函数,像数组的map,filter,reduce方法等,它们接受一个函数作为参数,并应用这个函数到列表的每一个元素
小丞同学
2021/08/16
1.4K0
JS中添加元素的方法
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/152078.html原文链接:https://javaforall.cn
全栈程序员站长
2022/06/25
9.8K0
JS中添加元素的方法
在Koa.js中实现文件上传的接口
文件上传是一个基本的功能,每个系统几乎都会有,比如上传图片、上传Excel等。那么在Node Koa应用中如何实现一个支持文件上传的接口呢?本文从环境准备开始、最后分别用 Postman 和一个HTML页面来测试。
张张
2019/12/27
4.9K0
在Node.js中逐行读取文件【纯技术】
在计算机科学中,文件是一种资源,用于在计算机的存储设备中离散地记录数据。Node.js不会以任何方式覆盖它,并且可以与文件系统中被视为文件的任何文件一起使用。
Jean
2019/09/24
7.9K0
vue文件中引入js_vue中require引入js
由于一些演示,需要对编码名称等可快速进行修改,需要页面方便配置。由于build后的vue项目基本已经看不出原样,因此需要创建一个文件,并在打包的时候不会进行编译。
全栈程序员站长
2022/11/08
12.2K0

相似问题

在cygwin/mingw上编译windows

12

glog不使用MinGW在Windows上编译

16

用OpenCV在Windows上编译MinGW

22

用QJson在Windows上编译MinGW

14

帮助使用GTK+在Windows上编译MinGW

13
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档