通过 HttpClient 使用 REST 服务

已完成

许多新式 Web 服务都实现了 REST 体系结构。 此结构使 Web 服务能够通过一系列定义明确的终结点公开操作和数据。 客户端应用发送到 REST Web 服务以检索、修改、创建或删除数据的请求使用一组预定义的谓词。 REST Web 服务以标准方式响应这些请求。 使用此方法可以更轻松地构造客户端应用。

REST 模型基于 HTTP 协议构建。 .NET MAUI 应用程序可以使用 HttpClient 类将请求发送到 REST Web 服务。 在本单元中,你将了解 HttpClient,并学习如何使用它与 REST Web 服务进行交互。

什么是 HttpClient 类?

HttpClient 是一个 .NET 类,应用可以使用它发送 HTTP 请求并从 REST Web 服务接收 HTTP 响应。 一组 URI 标识了 Web 服务公开的资源。 URI 将 Web 服务的地址与该地址中可用资源的名称组合在一起。

HttpClient 类使用基于任务的 API 来实现性能,并支持你访问请求消息中的信息,例如 HTTP 标头、状态代码以及包含正在发送和接收的实际数据的消息正文。

该图显示了客户端应用如何使用 HttpClient 对象发送和接收 HTTP 消息和响应

HttpClient 类可从 System.Net.Http 命名空间中获得。 应用可以使用默认构造函数创建 HttpClient 对象:

using System.Net.Http;
...

var client = new HttpClient();

使用 HttpClient 对象执行 CRUD 操作

REST Web 服务使客户端能够通过一组 HTTP 谓词对数据执行操作。 HTTP 谓词的任务是指示要对资源执行的预期操作。 有许多 HTTP 谓词,但最常见的四个为 POSTGETPUTDELETE。 服务可以实现这些谓词,使客户端应用程序能够通过执行创建、读取、更新和删除 (CRUD) 操作来管理对象的生命周期,如下所示:

  • POST 谓词表示想要创建新资源。

  • GET 谓词表示想要检索资源。

  • PUT 谓词表示想要更新资源。

  • DELETE 谓词表示想要删除资源。

该图显示了 REST 服务可以实现的基本 CRUD 操作,包括获取、发布、放置和删除。

使用 HttpClient 创建新资源

若要使用 HttpClient 创建新资源,可以使用 SendAsync 方法向其传递 HttpRequestMessage 对象。

HttpRequestMessage 用于对发送到 Web 服务的请求进行建模。 指定 HTTP 谓词、Web 服务的 URL,并填充要通过 HttpRequestMessage.Content 属性发送的任何有效负载。

HttpClient client = new HttpClient();

HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, url);
message.Content = JsonContent.Create<Part>(part);

HttpResponseMessage response = await client.SendAsync(message);

此代码片段执行以下任务:

  • 它创建一个名为 client 的 HttpClient 实例,用于发送消息
  • 它创建一个名为 message 的 HttpRequestMessage 实例,用于对消息进行建模。 message 包含 HTTP 谓词和 URL
  • 它使用 JsonContent.Create 函数设置 HttpRequestMessageContent 属性。 该函数会自动将 part 变量序列化为适合发送给 Web 服务的 JSON。
  • 它使用 HttpClient 对象发送消息。 返回的 HttpResponseMessage 包含状态代码等信息和 Web 服务返回的信息。

使用 HttpClient 读取资源

除了使用 HttpMethod.Get 初始化 HttpRequestMessage 之外,还可使用与上述相同的技术从 Web 服务读取资源。 但是,HttpClient 有几种便捷的方法可提供快捷方式。

若要使用 HTTPClient 读取资源,请使用 GetStringAsync 方法,如下一示例中所示:

HttpClient client = new HttpClient();

string text = await client.GetStringAsync("https://...");

GetStringAsync 方法采用引用资源的 URI,并以字符串形式返回响应。 字符串响应是应用请求的资源。 响应数据格式是所请求服务的默认格式,例如 JSON 或 XML。 应用可以通过添加 MediaTypeWithQualityHeaderValue 标头告诉 Web 服务它需要以特定格式返回数据。 例如,如果应用请求以 JSON 格式发送回数据,则可以使用以下代码:

HttpClient client = new HttpClient();

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

在此示例中,结果以字符串返回,并且仅包含响应消息正文。 若要获取包括标头、正文和状态代码在内的整个响应,请调用 GetAsync 方法。 数据作为 HttpResponseMessage 对象返回。

使用 HttpClient 更新资源

若要使用 HttpClient 更新资源,请使用通过 PUT 谓词初始化的 HttpRequestMessage。 以下代码类似于创建新资源所需的代码:

HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Put, url);

message.Content = JsonContent.Create<Part>(part);

HttpResponseMessage response = await client.SendAsync(message);

注意

POSTPUT 之间的根本区别是幂等性。 如果多次重复同一 PUT 请求,则同一资源将使用相同的数据进行更新,效果与仅发送一次请求相同。 如果多次发出同一 POST 请求,则结果将是 REST 服务正在创建的资源的多个副本。

使用 HttpClient 删除资源

若要使用 HttpClient 删除资源,请使用通过 DELETE 谓词初始化的 HttpRequestMessage 调用 SendAsync

HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Delete, url);

HttpResponseMessage response = await client.SendAsync(message);

响应包含标头、状态代码和已删除的对象。

处理来自请求的响应

所有 HTTP 请求都返回响应消息。 响应中的数据取决于应用发送的谓词。 例如,HTTP GET 请求的响应正文包含所请求资源的数据。

响应正文 POST 请求返回已创建资源的副本,但 PUT 请求的响应正文应为空。

应始终检查并处理响应消息中的状态代码。 如果此状态码在 200 范围内(200、201、202 等),则该操作被视为已成功,不过以后可能需要进一步的信息。

300 范围内的状态代码指示 Web 服务可能已将请求重定向到其他地址,可能是由于资源移动到其他位置。

400 范围内的状态代码指示客户端或应用程序错误。 例如,状态代码 403 表示 Web 服务要求对用户进行身份验证,但应用尚未进行身份验证。 当应用尝试访问不存在的资源时,将出现状态代码 404。

500 范围内的状态代码表示服务器端错误,例如服务不可用或太忙,无法处理请求。

通过 HttpClient 对象提交的请求所返回的 HttpResponseMessage 对象使处理不同状态代码的复杂性抽象化。 此代码片段演示如何验证响应消息中的状态代码是否指示成功,以及如何处理指示某些故障的状态代码。

static readonly HttpClient client = new HttpClient();

...
// Call asynchronous network methods in a try/catch block to handle exceptions.
try
{
    //... Initiate the HttpRequest

    HttpResponseMessage response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode(); // Check that the status code is in the 200 range. Throw an HttpRequestException if not
    
    string responseBody = await response.Content.ReadAsStringAsync();
    
    ... // Handle the response
}
catch(HttpRequestException e)
{
    ... // Handle any status codes that indicate an error. 
        // The status code is available in the field e.StatusCode
}

知识检查

1.

使用哪个 HTTP 谓词在 REST Web 服务中创建新资源?

2.

应调用 HttpResponseMessage 类的哪种方法来验证 HTTP 请求是否成功?