RestSharp v112 响应处理指南:RestResponse 与 RestResponse<T> 属性全解析
【免费下载链接】RestSharpSimple REST and HTTP API Client for .NET项目地址: https://gitcode.com/gh_mirrors/re/RestSharp
本指南以 RestSharp v112 版本文档的 "Handling responses" 一章为核心,系统讲解RestResponse与RestResponse<T>的每一个公开属性、ResponseStatus状态机的语义,以及IsSuccessful的正确判定逻辑。读完本文,你将能熟练读取响应头、正文与错误信息,正确区分 HTTP 错误与传输层错误,并在实际项目中使用泛型响应安全地获取反序列化结果。
一、响应对象的两种形态:RestResponse 与 RestResponse<T>
在 RestSharp 中,所有Execute{Method}Async函数都会返回RestResponse实例;而以Execute{Method}Async<T>命名的泛型重载则返回RestResponse<T>,其中T是响应对象(反序列化目标)的类型。这一点在 execute.md 中列举的调用签名中可以看到:
Task<RestResponse> ExecuteGetAsync(RestRequest request, CancellationToken cancellationToken) Task<RestResponse<T>> ExecuteGetAsync<T>(RestRequest request, CancellationToken cancellationToken)从源码看,两个类型是继承关系:RestResponse.cs 中定义了RestResponse<T>,它直接继承自RestResponse,并额外增加了一个Data属性;而 RestResponseBase.cs 中的RestResponseBase则承载了两个响应类型共享的全部公共属性。也就是说,无论你是否使用泛型重载,你拿到的响应对象都包含下面这套完整的属性。
二、RestResponse 完整属性表
RestResponse对象包含以下属性(内容直接继承自 response.md 官方文档):
| 属性 | 类型 | 说明 |
|---|---|---|
Request | RestRequest | 用于产生该响应的请求实例。 |
ContentType | string? | 响应内容类型(MIME)。响应无内容时为Null。 |
ContentLength | long? | 响应内容长度(字节)。响应无内容时为Null。 |
ContentEncoding | ICollection<string> | 内容编码集合。响应无内容时为空集合。 |
Content | string? | 以字符串表示的响应内容。响应无内容时为Null。 |
IsSuccessfulStatusCode | bool | 指示响应是否成功,即服务器未报告错误。 |
ResponseStatus | None、Completed、Error、TimedOut、Aborted | 响应完成状态。注意:状态为Completed的响应仍然可能携带 HTTP 错误。 |
IsSuccessful | bool | 当IsSuccessfulStatusCode为true且ResponseStatus为Completed时为True。 |
StatusDescription | string? | 响应状态描述(若可用)。 |
RawBytes | byte[]? | 以字节数组表示的响应内容。响应无内容时为Null。 |
ResponseUri | Uri? | 响应对应的 URI,发生重定向时可能与请求 URI 不同。 |
Server | string? | 响应的Server头值。 |
Cookies | CookieCollection? | 响应携带的 Cookie 集合(若有)。 |
Headers | HeaderParameter集合 | 响应头。 |
ContentHeaders | HeaderParameter集合 | 响应内容头。 |
ErrorMessage | string? | 尝试请求时产生的传输层或其他非 HTTP 错误。 |
ErrorException | Exception? | 执行请求时抛出的异常(若有)。 |
Version | Version? | 请求的 HTTP 协议版本。 |
RootElement | string? | 序列化响应内容的根元素,仅在反序列化器支持时生效。 |
属性之间的细微差别
Content与RawBytes:Content是经过解码的字符串形式,RawBytes是原始字节。需要保存文件、计算哈希或做二进制处理时优先使用RawBytes。Headers与ContentHeaders:前者来自HttpResponseMessage.Headers(如Server、Location),后者来自HttpResponseMessage.Content.Headers(如Content-Type、Content-Length)。二者在 RestResponse.cs 的FromHttpResponse中分别通过GetHeaderParameters()填充。ResponseUri:从源码可见其特殊逻辑——当状态码位于 300~399 且存在Location头时,会优先解析重定向后的 URI(相对地址会基于请求 URI 组合),见 RestResponse.cs。
三、ResponseStatus:五种完成状态
ResponseStatus枚举定义于 Enum.cs,五种取值的精确语义如下:
| 取值 | 语义 |
|---|---|
None | 不适用,通常表示请求尚未发出(构造RestResponseBase时的默认值,见 RestResponseBase.cs)。 |
Completed | 请求正常完成——HttpResponseMessage.IsSuccessStatusCode为true,或响应状态为404 Not Found。 |
Error | 请求失败——IsSuccessStatusCode为false(404 除外)。 |
TimedOut | 请求超时——超过RestRequest.Timeout规定的时间或HttpClient自身超时导致操作取消。 |
Aborted | 操作被取消,且原因不是超时。 |
需要特别注意文档中的警告:Completed并不等于业务成功。服务器返回500之类的错误码时,网络传输本身是"完成"的,此时ResponseStatus仍可能是Completed,但IsSuccessfulStatusCode为false。因此判断一次请求是否真正成功,请使用下一节的IsSuccessful,而不是单独看ResponseStatus。
一个快速判断的成功属性:IsSuccessful
IsSuccessful的定义在 RestResponseBase.cs:
public bool IsSuccessful => IsSuccessStatusCode && ResponseStatus == ResponseStatus.Completed;它要求两个条件同时成立:
- HTTP 状态码位于成功区间(
IsSuccessStatusCode == true); - 没有发生传输层错误、超时或取消(
ResponseStatus == Completed)。
换句话说,IsSuccessful是"服务器层面成功"与"传输层面成功"的合取。在编写业务代码时,用if (response.IsSuccessful)作为总入口,可以同时覆盖 HTTP 错误与网络异常两类失败场景。
四、RestResponse<T> 的额外属性:Data
RestResponse<T>在继承全部上述属性的基础上,额外增加一个属性:
| 属性 | 类型 | 说明 |
|---|---|---|
Data | T? | 反序列化后的响应对象。当响应无内容、反序列化器无法理解响应内容,或请求失败时,该属性为Null。 |
Data由ExecuteAsync<T>系列泛型重载在获得响应后调用客户端配置的反序列化器填充,其声明位于 RestResponse.cs:
public partial class RestResponse<T>(RestRequest request) : RestResponse(request) { public T? Data { get; set; } }典型用法:
var response = await client.ExecuteGetAsync<TResponse>(request, cancellationToken); if (response.IsSuccessful && response.Data is not null) { // 使用 response.Data 中的业务数据 } else { // 从 response.ErrorMessage / response.StatusCode 中提取失败原因 }需要注意,Data为Null有三种可能:响应体为空、反序列化失败、请求本身失败。所以即便IsSuccessful为真,也应防御性地对Data判空。
五、从源码看响应对象的构建过程
要真正理解这些属性的来源,可以阅读 RestResponse.cs 中的FromHttpResponse方法。RestSharp 在收到HttpResponseMessage后按以下步骤组装RestResponse:
- 读取响应流并转为字节数组(
stream.ReadAsBytes); - 将字节按客户端配置的编码(
options.Encoding)转为字符串,填充Content; - 逐项填充
ContentType、ContentLength、ContentEncoding、ContentHeaders、Headers、Server、StatusCode、StatusDescription、ResponseStatus、Version等; - 将 HTTP 响应头的
Location等用于计算ResponseUri; - 将
request.RootElement透传到RootElement,供支持根元素的反序列化器使用; - 依据
options.SetErrorExceptionOnUnsuccessfulStatusCode决定是否在非成功状态码时填充ErrorException。
这条构建路径解释了为什么Content、ContentType、ContentLength在"响应无内容"时会为Null——它们都来源于HttpResponseMessage.Content,而Content本身为空时这些属性自然无从谈起。
六、配套扩展方法:读取头与抛出错误
除了属性,RestSharp 还提供了与响应对象配套的扩展方法:
读取响应头
RestResponseExtensions.cs 提供了按名称读取头的方法(大小写不敏感匹配):
// 单个值 string? etag = response.GetHeaderValue("ETag"); // 多个值(同名头出现多次时) string[] values = response.GetHeaderValues("Set-Cookie"); // 内容头同理 string? contentType = response.GetContentHeaderValue("Content-Type"); string[] contentHeaders = response.GetContentHeaderValues("Content-Encoding");抛出错误异常
ResponseThrowExtension.cs 提供了ThrowIfError(),它会根据ResponseStatus生成对应异常并抛出:
Aborted→HttpRequestException("Request aborted", ErrorException)Error→ 返回原始ErrorExceptionTimedOut→TimeoutException("Request timed out", ErrorException)
该映射逻辑见 RestResponseBase.cs 的GetException()方法:
var response = await client.ExecuteAsync(request, cancellationToken); var checked = response.ThrowIfError(); // 失败时抛出,成功时原样返回这在"希望把异常处理交给调用方"的中间层代码中非常实用。
七、错误场景的判定要点与测试佐证
文档强调:Execute前缀的调用在服务器返回错误时不会抛异常,而是把错误信息放进响应对象,方便调用方检查(参见 execute.md 的 "Beware of errors" 提示)。因此,判断失败需要组合多个信号:
- 传输层/取消问题:看
ResponseStatus是否为TimedOut、Aborted、Error,以及ErrorMessage/ErrorException是否有值; - HTTP 层问题:看
IsSuccessfulStatusCode与StatusCode/StatusDescription; - 反序列化问题:泛型响应中
Data == null。
仓库中的测试也印证了这一模型,例如 ErrorMessageTests.cs 中直接断言response.ResponseStatus.Should().Be(ResponseStatus.Error),验证了传输错误会反映到ResponseStatus上。GetException()的实现也说明:只有在ResponseStatus明确为错误状态时才产生异常,这也是ThrowIfError只在真正失败时抛出的原因。
八、小结
- 非泛型
Execute{Method}Async返回RestResponse,泛型版本返回RestResponse<T>(额外带Data); IsSuccessful是"HTTP 成功 + 传输完成"的双重判定,是业务代码的首选判断入口;ResponseStatus的Completed不代表业务成功,必须结合IsSuccessfulStatusCode一起看;- 响应头、Cookie、原始字节、错误信息分别对应
Headers/ContentHeaders、Cookies、RawBytes、ErrorMessage/ErrorException属性; - 需要把错误转为异常时,可以使用
ThrowIfError()扩展方法。
建议进一步阅读 execute.md(如何发起请求)、error-handling.md(错误处理策略)以及 serialization.md(Data反序列化机制),配合 RestResponse.cs 与 RestResponseBase.cs 的源码,即可完整掌握 RestSharp 的响应处理链路。
【免费下载链接】RestSharpSimple REST and HTTP API Client for .NET项目地址: https://gitcode.com/gh_mirrors/re/RestSharp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考