Net Core HttpClient 全面教程系列-使用响应数据
此篇仍然使用录屏方式。有条友说暗黑主题的录屏看不清,因为代码在习惯上使用暗黑主题,所以这篇不变。如果还有反馈,下次就使用明亮主题。
这篇主要是使用远程WebAPI响应数据。当然,WebAPI的返回,首先要处理请求超时、服务器错误等异常情况。
1、初始化及全局设置
//初始化,只执行一次
// 引用nuget包和类库文件
#r "./Publish/HttpClientStudy.Model/HttpClientStudy.Model.dll"
#r "./Publish/HttpClientStudy.Core/HttpClientStudy.Core.dll"
//全局引用
global using System;
global using System.Collections;
global using System.Linq;
global using System.Linq.Expressions;
global using System.Threading;
global using System.Threading.Tasks;
global using System.Net.Http;
global using System.Net.Mime;
global using System.Net.Http.Json;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using HttpClientStudy.Config;
global using HttpClientStudy.Model;
global using HttpClientStudy.Core;
global using HttpClientStudy.Core.Utilities;
//全局变量
var webApiBaseUrl = WebApiConfigManager.GetWebApiConfig().BaseUrl;
var workDir = Environment.CurrentDirectory;
var fullPath = System.IO.Path.GetFullPath("./Publish/HttpClientStudy.WebApp/HttpClientStudy.WebApp.exe", workDir);
//全局共享静态 HttpClient 对象
public static HttpClient SharedClient = new HttpClient(new SocketsHttpHandler(){ PooledConnectionIdleTimeout = TimeSpan.FromSeconds(30)})
{
BaseAddress = new Uri(WebApiConfigManager.GetWebApiConfig().BaseUrl),
};
//启动已发布的WebApi项目
{
Console.WriteLine("启动WebApi项目");
var startMessage = AppUtility.RunWebApiExeFile(fullPath);
Console.WriteLine(startMessage);
}
2、处理响应状态
//判断响应码:正常
{
var response = await SharedClient.GetAsync("api/Normal/GetAccount?id=1");
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(#34;响应码正常:{content}");
}
}
//判断响应码:非正常
{
var response = await SharedClient.GetAsync("api/Normal/GetAccount?id=b");
if(response.StatusCode != System.Net.HttpStatusCode.OK)
{
Console.WriteLine(#34;响应码异常:状态码 {response.StatusCode}");
}
}
//确保正确响应:正常
{
var response = await SharedClient.GetAsync("api/Normal/GetAccount?id=1");
//确保异常
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<BaseResult<Account>>();
//result.Display();
Console.WriteLine(#34;响应正常:内容为 {result}");
}
//确保正确响应:异常
{
try
{
var response = await SharedClient.GetAsync("api/Normal/GetAccount?id=c");
//确保异常
response.EnsureSuccessStatusCode();
//result.Display();
var result = await response.Content.ReadFromJsonAsync<BaseResult<Account>>();
Console.WriteLine(#34;响应正常:内容为 {result}");
}
catch(Exception e)
{
Console.WriteLine(#34;请求异常:{e.Message}");
}
}
//使用 ry catch 捕获所有异常
{
try
{
var result = await SharedClient.GetFromJsonAsync<BaseResult<Account>>("api/Normal/GetAccount?id=a");
//result.Display();
Console.WriteLine(#34;响应正常:内容为 {result}");
}
catch(Exception e)
{
Console.WriteLine(#34;请求异常:{e.Message}");
}
finally
{
//收发业务
}
}
3、处理异常响应
3.1 try catch
//try catch 常规异常处理
{
try
{
var response = await SharedClient.GetAsync("api/Normal/GetAccount?id=c");
//确保异常
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<BaseResult<Account>>();
Console.WriteLine(#34;响应正常:内容为 {result}");
}
catch(Exception e)
{
Console.WriteLine(#34;接口异常:{e.Message}");
}
finally
{
//清理
}
}
3.2 管道统一处理
//异常处理管理中间件
public class ExceptionDelegatingHandler : DelegatingHandler
{
protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine("ExceptionDelegatingHandler -> Send -> Added Token");
HttpResponseMessage response = new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);
try
{
response = base.Send(request, cancellationToken);
response.EnsureSuccessStatusCode();
}
catch(Exception ex)
{
//统一异常处理,当然也可以分类别处理
Console.WriteLine(#34;中间件中,接口调用异常:{ex.Message}");
}
finally
{
Console.WriteLine("ExceptionDelegatingHandler -> Send -> After");
}
return response;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine("ExceptionDelegatingHandler -> SendAsync -> Before");
HttpResponseMessage response = new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);
try
{
response = await base.SendAsync(request, cancellationToken);
//可以根据状态码,分别进行处理
response.EnsureSuccessStatusCode();
}
catch(Exception ex)
{
//统一异常处理,当然也可以分类别处理
//可以重试等操作
Console.WriteLine(#34;中间件中,接口调用异常:{ex.Message}");
}
finally
{
Console.WriteLine("ExceptionDelegatingHandler -> Send -> After");
}
return response;
}
}
//使用异常管道,发送请求
{
//使用管道中间件,统一处理
ExceptionDelegatingHandler exceptionHandler = new ExceptionDelegatingHandler()
{
InnerHandler = new SocketsHttpHandler()
};
HttpClient clientWithExceptionHandler = new HttpClient(exceptionHandler)
{
BaseAddress = new Uri(webApiBaseUrl),
};
//发送请求
var response = await clientWithExceptionHandler.GetAsync("api/Normal/GetAccount?id=c");
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = await response.Content.ReadFromJsonAsync<BaseResult<Account>>();
Console.WriteLine(#34;响应正常:内容为 {result}");
}
else
{
Console.WriteLine(#34;接口异常:状态码 {response.StatusCode}");
}
}
3.3 类型化客户端统一处理
//类型化客户端
public class HelloApiService
{
public HttpClient Client { get; set; }
public HelloApiService(HttpClient httpClient)
{
Client = httpClient;
}
//处理异常:也可以结合AOP,进行统一拦截处理
public async Task<string> Ping()
{
try
{
var content = await Client.GetStringAsync("/api/Hello/Ping2");
return content;
}
catch(Exception ex)
{
return #34;远程调用异常:{ex.Message}";
}
}
}
//使用
{
//注册类型化客户端
var services = new ServiceCollection();
services.AddHttpClient<HelloApiService>(client =>
{
client.BaseAddress = new Uri(webApiBaseUrl);
})
.ConfigureHttpClient(client=>
{
client.Timeout = TimeSpan.FromSeconds(1);
});
//使用类型化客户端,进行远程调用
var apiService = services.BuildServiceProvider().GetService<HelloApiService>();
var s = await apiService.Ping();
Console.WriteLine(s);
}
4、处理响应数据
4.1 接收响应头数据
//响应头信息
{
var response = await SharedClient.GetAsync("api/Normal/GetAccount?id=1");
Console.WriteLine("响应头:");
foreach(var header in response.Headers)
{
var headerValues = string.Join(",", header.Value);
Console.WriteLine(#34;{header.Key} = {headerValues}");
}
}
4.2 接收响应体数据
//响应体数据(json为例)
{
var response = await SharedClient.GetAsync("api/Normal/GetAccount?id=1");
//获取响应体内容
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(#34;响应体数据:{content}");
}