当前位置: 首页 > news >正文

网站公司建设网站收费模块怎么做网站宣传

网站公司建设网站收费模块,怎么做网站宣传,门户网站建设的必要性,有哪些游戏网站如今#xff0c;基于云、微服务或物联网的应用程序通常依赖于通过网络与其他系统通信。每个服务都在自己的进程中运行#xff0c;并解决一组有限的问题。服务之间的通信是基于一种轻量级的机制#xff0c;通常是一个 HTTP 资源 API。从.NET 开发人员的角度来看#xff0c;我… 如今基于云、微服务或物联网的应用程序通常依赖于通过网络与其他系统通信。每个服务都在自己的进程中运行并解决一组有限的问题。服务之间的通信是基于一种轻量级的机制通常是一个 HTTP 资源 API。从.NET 开发人员的角度来看我们希望以可分发包的形式提供一种一致的、可管理的方式来集成特定的服务。最好的方法是将我们开发的服务集成代码以 NuGet 包的形式提供并与其他人、团队、甚至组织分享。在这篇文章中我将分享在.NET 6 中创建和使用 HTTP 客户端 SDK 的方方面面。客户端 SDK 在远程服务之上提供了一个有意义的抽象层。本质上它允许进行远程过程调用RPC。客户端 SDK 的职责是序列化一些数据将其发送到远端目的地以及反序列化接收到的数据并处理响应。HTTP 客户端 SDK 与 API 一同使用加速 API 集成过程提供一致、标准的方法让服务所有者可以部分地控制消费 API 的方式。编写一个 HTTP 客户端 SDK在本文中我们将编写一个完备的Dad Jokes API客户端为的是提供老爸笑话让我们来玩一玩。源代码在GitHub上。在开发与 API 一起使用的客户端 SDK 时最好从接口契约API 和 SDK 之间入手public interface IDadJokesApiClient{ TaskJokeSearchResponse SearchAsync( string term, CancellationToken cancellationToken);TaskJoke GetJokeByIdAsync( string id, CancellationToken cancellationToken);TaskJoke GetRandomJokeAsync(CancellationToken cancellationToken);} public class JokeSearchResponse{ public bool Success { get; init; }public ListJoke Body { get; init; } new();} public class Joke{ public string Punchline { get; set; } default!;public string Setup { get; set; } default!;public string Type { get; set; } default!;}复制代码契约是基于你要集成的 API 创建的。我一般建议遵循健壮性原则和最小惊奇原则开发通用的 API。但如果你想根据自己的需要修改和转换数据契约也是完全可以的只需从消费者的角度考虑即可。HttpClient 是基于 HTTP 进行集成的基础。它包含你处理HTTP抽象时所需要的一切东西。public class DadJokesApiClient : IDadJokesApiClient{ private readonly HttpClient httpClient;public DadJokesApiClient(HttpClient httpClient) this.httpClient httpClient;}复制代码通常HTTP API 会使用 JSON这就是为什么从.NET 5 开始BCL 增加了System.Net.Http.Json命名空间。它为HttpClient和HttpContent提供了许多扩展方法让我们可以使用System.Text.Json进行序列化和反序列化。如果没有什么复杂的特殊需求我建议你使用System.Net.Http.Json因为它能让你免于编写模板代码。那不仅很枯燥而且也很难保证高效、没有 Bug。我建议你读下 Steves Gordon 的博文“使用HttpClient发送和接收JSON”public async TaskJoke GetRandomJokeAsync(CancellationToken cancellationToken){ var jokes await this.httpClient.GetFromJsonAsyncJokeSearchResponse( ApiUrlConstants.GetRandomJoke, cancellationToken);if (jokes is { Body.Count: 0 } or { Success: false }) { // 对于这种情况考虑创建自定义的异常 throw new InvalidOperationException(This API is no joke.); }return jokes.Body.First();}复制代码小提示你可以创建一些集中式的地方来管理端点 URL像下面这样public static class ApiUrlConstants{ public const string JokeSearch /joke/search;public const string GetJokeById /joke;public const string GetRandomJoke /random/joke;}复制代码小提示如果你需要处理复杂的 URI请使用Flurl。它提供了流畅的 URL 构建URL-building体验public async TaskJoke GetJokeByIdAsync(string id, CancellationToken cancellationToken){ // ${ApiUrlConstants.GetJokeById}/{id} var path ApiUrlConstants.GetJokeById.AppendPathSegment(id);var joke await this.httpClient.GetFromJsonAsyncJoke(path, cancellationToken);return joke ?? new();}复制代码接下来我们必须指定所需的头文件和其他所需的配置。我们希望提供一种灵活的机制来配置作为 SDK 组成部分的HttpClient。在这种情况下我们需要在自定义头中提供证书并指定一个众所周知的“Accept”。小提示将高层的构建块暴露为HttpClientExtensions。这更便于发现特定于 API 的配置。例如如果你有一个自定义的授权机制则 SDK 应提供支持至少要提供相关的文档。public static class HttpClientExtensions{ public static HttpClient AddDadJokesHeaders( this HttpClient httpClient, string host, string apiKey) { var headers httpClient.DefaultRequestHeaders; headers.Add(ApiConstants.HostHeader, new Uri(host).Host); headers.Add(ApiConstants.ApiKeyHeader, apiKey);return httpClient; }}复制代码客户端生命周期为了构建DadJokesApiClient我们需要创建一个HttpClient。如你所知HttpClient实现了IDisposable因为它有一个非托管的底层资源——TCP 连接。在一台机器上同时打开的并发 TCP 连接数量是有限的。这种考虑也带来了一个重要的问题——“我应该在每次需要时创建HttpClient还是只在应用程序启动时创建一次”HttpClient是一个共享对象。这就意味着在底层它是可重入和线程安全的。与其每次执行时新建一个HttpClient实例不如共享一个HttpClient实例。然而这种方法也有一系列的问题。例如客户端在应用程序的生命周期内会保持连接打开它不会遵守DNS TTL设置而且它将永远无法收到 DNS 更新。所以这也不是一个完美的解决方案。你需要管理一个不定时销毁连接的 TCP 连接池以获取 DNS 更新。这正是HttpClientFactory所做的。官方文档将HttpClientFactory描述为“一个专门用于创建可在应用程序中使用的HttpClient实例的工厂”。我们稍后将介绍如何使用它。每次从IHttpClientFactory获取一个HttpClient对象时都会返回一个新的实例。但是每个HttpClient都使用一个被IHttpClientFactory池化并重用的 HttpMessageHandler减少了资源消耗。处理程序的池化是值得的因为通常每个处理程序都要管理其底层的 HTTP 连接。有些处理程序还会无限期地保持连接开放防止处理程序对 DNS 的变化做出反应。HttpMessageHandler有一个有限的生命周期。下面我们看下在使用由依赖注入DI管理的HttpClient时HttpClientFactory是如何发挥作用的。消费 API 客户端在我们的例子中消费 API 的一个基本场景是无依赖注入容器的控制台应用程序。这里的目标是让消费者以最快的方式来访问已有的 API。创建一个静态工厂方法来创建一个 API 客户端。public static class DadJokesApiClientFactory{ public static IDadJokesApiClient Create(string host, string apiKey) { var httpClient new HttpClient() { BaseAddress new Uri(host); } ConfigureHttpClient(httpClient, host, apiKey);return new DadJokesApiClient(httpClient); }internal static void ConfigureHttpClient( HttpClient httpClient, string host, string apiKey) { ConfigureHttpClientCore(httpClient); httpClient.AddDadJokesHeaders(host, apiKey); }internal static void ConfigureHttpClientCore(HttpClient httpClient) { httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new(application/json)); }}复制代码这样我们可以从控制台应用程序使用IDadJokesApiClient var host https://dad-jokes.p.rapidapi.com;var apiKey token; var client DadJokesApiClientFactory.Create(host, apiKey);var joke await client.GetRandomJokeAsync(); Console.WriteLine(${joke.Setup} {joke.Punchline});消费 API 客户端HttpClientFactory下一步是将HttpClient配置为依赖注入容器的一部分。关于这一点网上有很多不错的内容我就不做详细讨论了。Steve Gordon 也有一篇非常好的文章“ASP.NET Core中的HttpClientFactory”。为了使用 DI 添加一个池化的HttpClient实例你需要使用来自Microsoft.Extensions.Http的IServiceCollection.AddHttpClient。提供一个自定义的扩展方法用于在 DI 中添加类型化的HttpClient。public static class ServiceCollectionExtensions{ public static IHttpClientBuilder AddDadJokesApiClient( this IServiceCollection services, ActionHttpClient configureClient) services.AddHttpClientIDadJokesApiClient, DadJokesApiClient((httpClient) { DadJokesApiClientFactory.ConfigureHttpClientCore(httpClient); configureClient(httpClient); });}复制代码使用扩展方法的方式如下var host https://da-jokes.p.rapidapi.com;var apiKey token; var services new ServiceCollection(); services.AddDadJokesApiClient(httpClient { httpClient.BaseAddress new(host); httpClient.AddDadJokesHeaders(host, apiKey);}); var provider services.BuildServiceProvider();var client provider.GetRequiredServiceIDadJokesApiClient(); var joke await client.GetRandomJokeAsync(); logger.Information(${joke.Setup} {joke.Punchline});复制代码如你所见IHttpClientFactory 可以在 ASP.NET Core 之外使用。例如控制台应用程序、worker、lambdas 等。让我们看下它运行有趣的是由 DI 创建的客户端会自动记录发出的请求使得开发和故障排除都变得非常容易。如果你操作日志模板的格式并添加SourceContext和EventId就会看到HttpClientFactory自己添加了额外的处理程序。当你试图排查与 HTTP 请求处理有关的问题时这很有用。{SourceContext}[{EventId}] // 模式 System.Net.Http.HttpClient.IDadJokesApiClient.LogicalHandler [{ Id: 100, Name: RequestPipelineStart }] System.Net.Http.HttpClient.IDadJokesApiClient.ClientHandler [{ Id: 100, Name: RequestStart }] System.Net.Http.HttpClient.IDadJokesApiClient.ClientHandler [{ Id: 101, Name: RequestEnd }]System.Net.Http.HttpClient.IDadJokesApiClient.LogicalHandler [{ Id: 101, Name: RequestPipelineEnd }]复制代码最常见的场景是 Web 应用程序。下面是.NET 6 MinimalAPI 示例var builder WebApplication.CreateBuilder(args);var services builder.Services;var configuration builder.Configuration;var host configuration[DadJokesClient:host]; services.AddDadJokesApiClient(httpClient { httpClient.BaseAddress new(host); httpClient.AddDadJokesHeaders(host, configuration[DADJOKES_TOKEN]);}); var app builder.Build(); app.MapGet(/, async (IDadJokesApiClient client) await client.GetRandomJokeAsync()); app.Run();{ punchline: They are all paid actors anyway, setup: We really shouldnt care what people at the Oscars say, type: actor}复制代码扩展 HTTP 客户端 SDK通过 DelegatingHandler 添加横切关注点HttpClient还提供了一个扩展点一个消息处理程序。它是一个接收 HTTP 请求并返回 HTTP 响应的类。有许多问题都可以表示为横切关注点。例如日志、身份认证、缓存、头信息转发、审计等等。面向方面的编程旨在将横切关注点封装成方面以保持模块化。通常情况下一系列的消息处理程序被链接在一起。第一个处理程序接收一个 HTTP 请求做一些处理然后将请求交给下一个处理程序。有时候响应创建后会回到链条上游。// 支持大部分应用程序最常见的需求public abstract class HttpMessageHandler : IDisposable{}// 将一个处理程序加入到处理程序链public abstract class DelegatingHandler : HttpMessageHandler{}任务假如你需要从 ASP.NET Core 的HttpContext复制一系列头信息并将它们传递给 Dad Jokes API 客户端发出的所有外发请求。public class HeaderPropagationMessageHandler : DelegatingHandler{ private readonly HeaderPropagationOptions options; private readonly IHttpContextAccessor contextAccessor;public HeaderPropagationMessageHandler( HeaderPropagationOptions options, IHttpContextAccessor contextAccessor) { this.options options; this.contextAccessor contextAccessor; }protected override TaskHttpResponseMessage SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { if (this.contextAccessor.HttpContext ! null) { foreach (var headerName in this.options.HeaderNames) { var headerValue this.contextAccessor .HttpContext.Request.Headers[headerName];request.Headers.TryAddWithoutValidation( headerName, (string[])headerValue); } }return base.SendAsync(request, cancellationToken); }} public class HeaderPropagationOptions{ public IListstring HeaderNames { get; set; } new Liststring();}复制代码我们想把一个DelegatingHandler“插入”到HttpClient请求管道中。对于非IttpClientFactory场景我们希望客户端能够指定一个DelegatingHandler列表来为HttpClient建立一个底层链。//DadJokesApiClientFactory.cspublic static IDadJokesApiClient Create( string host, string apiKey, params DelegatingHandler[] handlers){ var httpClient new HttpClient();if (handlers.Length 0) { _ handlers.Aggregate((a, b) { a.InnerHandler b; return b; }); httpClient new(handlers[0]); } httpClient.BaseAddress new Uri(host);ConfigureHttpClient(httpClient, host, apiKey);return new DadJokesApiClient(httpClient);}复制代码这样在没有 DI 容器的情况下可以像下面这样扩展 DadJokesApiClient var loggingHandler new LoggingMessageHandler(); //最外层var authHandler new AuthMessageHandler();var propagationHandler new HeaderPropagationMessageHandler();var primaryHandler new HttpClientHandler(); // HttpClient使用的默认处理程序 DadJokesApiClientFactory.Create( host, apiKey, loggingHandler, authHandler, propagationHandler, primaryHandler); // LoggingMessageHandler ➝ AuthMessageHandler ➝ HeaderPropagationMessageHandler ➝ HttpClientHandler复制代码另一方面在 DI 容器场景中我们希望提供一个辅助的扩展方法使用IHttpClientBuilder.AddHttpMessageHandler轻松插入HeaderPropagationMessageHandler。public static class HeaderPropagationExtensions{ public static IHttpClientBuilder AddHeaderPropagation( this IHttpClientBuilder builder, ActionHeaderPropagationOptions configure) { builder.Services.Configure(configure); builder.AddHttpMessageHandler((sp) { return new HeaderPropagationMessageHandler( sp.GetRequiredServiceIOptionsHeaderPropagationOptions().Value, sp.GetRequiredServiceIHttpContextAccessor()); });return builder; }}复制代码扩展后的 MinimalAPI 示例如下所示var builder WebApplication.CreateBuilder(args);var services builder.Services;var configuration builder.Configuration;var host configuration[DadJokesClient:host]; services.AddDadJokesApiClient(httpClient { httpClient.BaseAddress new(host); httpClient.AddDadJokesHeaders(host, configuration[DADJOKES_TOKEN]);}).AddHeaderPropagation(o o.HeaderNames.Add(X-Correlation-ID)); var app builder.Build(); app.MapGet(/, async (IDadJokesApiClient client) await client.GetRandomJokeAsync()); app.Run();复制代码有时像这样的功能会被其他服务所重用。你可能想更进一步把所有共享的代码都提取到一个公共的 NuGet 包中并在 HTTP 客户端 SDK 中使用它。第三方扩展我们可以编写自己的消息处理程序但.NET OSS 社区也提供了许多有用的 NuGet 包。以下是我最喜欢的。弹性模式——重试、缓存、回退等很多时候在一个系统不可靠的世界里你需要通过加入一些弹性策略来确保高可用性。幸运的是我们有一个内置的解决方案可以在.NET 中构建和定义策略那就是Polly。Polly 提供了与IHttpClientFactory开箱即用的集成。它使用了一个便捷的方法IHttpClientBuilder.AddTransientHttpErrorPolicy。它配置了一个策略来处理 HTTP 调用的典型错误HttpRequestException HTTP 5XX 状态码服务器错误、HTTP 408 状态码请求超时。services.AddDadJokesApiClient(httpClient { httpClient.BaseAddress new(host);}).AddTransientHttpErrorPolicy(builder builder.WaitAndRetryAsync(new[]{ TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10)}));复制代码例如可以使用重试和断路器模式主动处理瞬时错误。通常当下游服务有望自我纠正时我们会使用重试模式。重试之间的等待时间对于下游服务而言是一个恢复稳定的窗口。重试经常使用指数退避算法。这纸面上听起来不错但在现实世界的场景中重试模式的使用可能过度了。额外的重试可能导致额外的负载或峰值。在最坏的情况下调用者的资源可能会被耗尽或过分阻塞等待永远不会到来的回复导致上游发生了级联故障。这就是断路器模式发挥作用的时候了。它检测故障等级并在故障超过阈值时阻止对下游服务的调用。如果没有成功的机会就可以使用这种模式例如当一个子系统完全离线或不堪重负时。断路器的理念非常简单虽然你可能会以它为基础构建一些更复杂的东西。当故障超过阈值时调用就会断开因此我们不是处理请求而是实践快速失败的方法立即抛出一个异常。Polly 真的很强大它提供了一种组合弹性策略的方法见PolicyWrap。下面是一个可能对你有用的策略分类设计可靠的系统可能是一项非常具有挑战性的任务我建议你自己研究下这个问题。这里有一个很好的介绍——.NET微服务架构电子书实现弹性应用程序。OAuth2/OIDC 中的身份认证如果你需要管理用户和客户端访问令牌我建议使用IdentityModel.AspNetCore。它可以帮你获取、缓存和轮换令牌详情参见文档。// 添加用户和客户端访问令牌管理services.AddAccessTokenManagement(options { options.Client.Clients.Add(identity-provider, new ClientCredentialsTokenRequest { Address https://demo.identityserver.io/connect/token, ClientId my-awesome-service, ClientSecret secret, Scope api });});// 使用托管的客户端访问令牌注册HTTP客户端// 向HTTP客户端注册添加令牌访问处理程序services.AddDadJokesApiClient(httpClient { httpClient.BaseAddress new(host);}).AddClientAccessTokenHandler();复制代码测试 HTTP 客户端 SDK至此对于设计和编写 HTTP 客户端 SDK你应该已经比较熟悉了。剩下的工作就只是写一些测试来确保其行为符合预期了。请注意跳过广泛的单元测试编写更多的集成或 e2e 来确保集成的正确性或许也不错。现在我将展示如何对DadJokesApiClient进行单元测试。如前所述HttpClient是可扩展的。此外我们可以用测试版本代替标准的HttpMessageHandler。这样我们就可以使用模拟服务而不是通过网络发送实际的请求。这种技术提供了大量的可能因为我们可以模拟各种在正常情况下是很难复现的HttpClient行为。我们定义一个可重用的方法用于创建一个 HttpClient 模拟并作为一个依赖项传递给DadJokesApiClient。public static class TestHarness{ public static MockHttpMessageHandler CreateMessageHandlerWithResultT( T result, HttpStatusCode code HttpStatusCode.OK) { var messageHandler new MockHttpMessageHandler(); messageHandler.Protected() .SetupTaskHttpResponseMessage( SendAsync, ItExpr.IsAnyHttpRequestMessage(), ItExpr.IsAnyCancellationToken()) .ReturnsAsync(new HttpResponseMessage() { StatusCode code, Content new StringContent(JsonSerializer.Serialize(result)), });return messageHandler; }public static HttpClient CreateHttpClientWithResultT( T result, HttpStatusCode code HttpStatusCode.OK) { var httpClient new HttpClient(CreateMessageHandlerWithResult(result, code).Object) { BaseAddress new(https://api-client-under-test.com), };Return httpClient; }}复制代码从这点来看单元测试是个非常简单的过程public class DadJokesApiClientTests{ [Theory, AutoData] public async Task GetRandomJokeAsync_SingleJokeInResult_Returned(Joke joke) { // Arrange var response new JokeSearchResponse { Success true, Body new() { joke } }; var httpClient CreateHttpClientWithResult(response); var sut new DadJokesApiClient(httpClient);// Act var result await sut.GetRandomJokeAsync();// Assert result.Should().BeEquivalentTo(joke); }[Fact] public async Task GetRandomJokeAsync_UnsuccessfulJokeResult_ExceptionThrown() { // Arrange var response new JokeSearchResponse(); var httpClient CreateHttpClientWithResult(response); var sut new DadJokesApiClient(httpClient);// Act // Assert await FluentActions.Invoking(() sut.GetRandomJokeAsync()) .Should().ThrowAsyncInvalidOperationException(); }}使用HttpClient是最灵活的方法。你可以完全控制与 API 的集成。但是也有一个缺点你需要编写大量的样板代码。在某些情况下你要集成的 API 并不重要所以你并不需要HttpClient、HttpRequestMessage、HttpResponseMessage所提供的所有功能。优点➕可以完全控制行为和数据契约。你甚至可以编写一个“智能”API 客户端如果有需要的话在特殊情况下你可以把一些逻辑移到 SDK 里。例如你可以抛出自定义的异常转换请求和响应提供默认头信息等等。可以完全控制序列化和反序列化过程。易于调试和排查问题。堆栈容易跟踪你可以随时启动调试器看看后台正在发生的事情。缺点➖需要编写大量的重复代码。需要有人维护代码库以防 API 有变化和 Bug。这是一个繁琐的、容易出错的过程。使用声明式方法编写 HTTP 客户端 SDK代码越少Bug 越少。Refit是一个用于.NET 的、自动化的、类型安全的 REST 库。它将 REST API 变成一个随时可用的接口。Refit 默认使用System.Text.Json作为 JSON 序列化器。每个方法都必须有一个 HTTP 属性提供请求方法和相对应的 URL。using Refit; public interface IDadJokesApiClient{ /// summary /// 根据词语搜索笑话。 /// /summary [Get(/joke/search)] TaskJokeSearchResponse SearchAsync( string term, CancellationToken cancellationToken default);/// summary /// 根据id获取一个笑话。 /// /summary [Get(/joke/{id})] TaskJoke GetJokeByIdAsync( string id, CancellationToken cancellationToken default);/// summary /// 随机获取一个笑话。 /// /summary [Get(/random/joke)] TaskJokeSearchResponse GetRandomJokeAsync( CancellationToken cancellationToken default);}复制代码Refit 根据Refit.HttpMethodAttribute提供的信息生成实现IDadJokesApiClient接口的类型。消费 API 客户端Refit该方法与平常的HttpClient集成方法相同但我们不是手动构建一个客户端而是使用 Refit 提供的静态方法。public static class DadJokesApiClientFactory{ public static IDadJokesApiClient Create( HttpClient httpClient, string host, string apiKey) { httpClient.BaseAddress new Uri(host);ConfigureHttpClient(httpClient, host, apiKey);return RestService.ForIDadJokesApiClient(httpClient); } // ...}对于 DI 容器场景我们可以使用Refit.HttpClientFactoryExtensions.AddRefitClient扩展方法。public static class ServiceCollectionExtensions{ public static IHttpClientBuilder AddDadJokesApiClient( this IServiceCollection services, ActionHttpClient configureClient) { var settings new RefitSettings() { ContentSerializer new SystemTextJsonContentSerializer(new JsonSerializerOptions() { PropertyNameCaseInsensitive true, WriteIndented true, }) };return services.AddRefitClientIDadJokesApiClient(settings).ConfigureHttpClient((httpClient) { DadJokesApiClientFactory.ConfigureHttpClient(httpClient); configureClient(httpClient); }); }}用法如下var builder WebApplication.CreateBuilder(args);var configuration builder.Configuration; Log.Logger new LoggerConfiguration().WriteTo.Console().CreateBootstrapLogger();builder.Host.UseSerilog((ctx, cfg) cfg.WriteTo.Console()); var services builder.Services; services.AddDadJokesApiClient(httpClient { var host configuration[DadJokesClient:host]; httpClient.BaseAddress new(host); httpClient.AddDadJokesHeaders(host, configuration[DADJOKES_TOKEN]);}); var app builder.Build(); app.MapGet(/, async TaskJoke (IDadJokesApiClient client) { var jokeResponse await client.GetRandomJokeAsync();return jokeResponse.Body.First(); // unwraps JokeSearchResponse}); app.Run();注意由于生成的客户端其契约应该与底层数据契约相匹配所以我们不再控制契约的转换这项职责被托付给了消费者。让我们看看上述代码在实践中是如何工作的。MinimalAPI 示例的输出有所不同因为我加入了 Serilog 日志。{ punchline: Forgery., setup: Why was the blacksmith charged with?, type: forgery}复制代码同样这种方法也有其优缺点优点➕便于使用和开发 API 客户端。高度可配置。可以非常灵活地把事情做好。不需要额外的单元测试。缺点➖故障排查困难。有时候很难理解生成的代码是如何工作的。例如在配置上存在不匹配。需要团队其他成员了解如何阅读和编写使用 Refit 开发的代码。对于中/大型 API 来说仍然有一些时间消耗。感兴趣的读者还可以了解下RestEase。使用自动化方法编写 HTTP 客户端 SDK有一种方法可以完全自动地生成 HTTP 客户端 SDK。OpenAPI/Swagger 规范使用 JSON 和 JSON Schema 来描述 RESTful Web API。NSwag项目提供的工具可以从这些 OpenAPI 规范生成客户端代码。所有东西都可以通过 CLI通过 NuGet 工具、构建目标或 NPM 分发自动化。Dad Jokes API 不提供 OpenAPI所以我手动编写了一个。幸运的是这很容易openapi: 3.0.2info: title: Dad Jokes API version: 1.0servers: - url: https://dad-jokes.p.rapidapi.compaths: /joke/{id}: get: description: operationId: GetJokeById parameters: - name: id in: path description: required: true schema: type: string responses: 200: description: successful operation content: application/json: schema: $ref: #/components/schemas/Joke /random/joke: get: description: operationId: GetRandomJoke parameters: [] responses: 200: description: successful operation content: application/json: schema: $ref: #/components/schemas/JokeResponse /joke/search: get: description: operationId: SearchJoke parameters: [] responses: 200: description: successful operation content: application/json: schema: $ref: #/components/schemas/JokeResponsecomponents: schemas: Joke: type: object required: - _id - punchline - setup - type properties: _id: type: string type: type: string setup: type: string punchline: type: string JokeResponse: type: object properties: sucess: type: boolean body: type: array items: $ref: #/components/schemas/Joke复制代码现在我们希望自动生成 HTTP 客户端 SDK。让我们借助NSwagStudio。生成的IDadJokesApiClient 类似下面这样简洁起见删除了 XML 注释[System.CodeDom.Compiler.GeneratedCode(NSwag, 13.10.9.0 (NJsonSchema v10.4.1.0 (Newtonsoft.Json v12.0.0.0)))] public partial interface IDadJokesApiClient { System.Threading.Tasks.TaskJoke GetJokeByIdAsync(string id); System.Threading.Tasks.TaskJoke GetJokeByIdAsync(string id, System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.TaskJokeResponse GetRandomJokeAsync(); System.Threading.Tasks.TaskJokeResponse GetRandomJokeAsync(System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.TaskJokeResponse SearchJokeAsync(); System.Threading.Tasks.TaskJokeResponse SearchJokeAsync(System.Threading.CancellationToken cancellationToken); }复制代码同样我们希望把类型化客户端的注册作为一个扩展方法来提供。public static class ServiceCollectionExtensions{ public static IHttpClientBuilder AddDadJokesApiClient( this IServiceCollection services, ActionHttpClient configureClient) services.AddHttpClientIDadJokesApiClient, DadJokesApiClient( httpClient configureClient(httpClient));}用法如下var builder WebApplication.CreateBuilder(args);var configuration builder.Configuration;var services builder.Services; services.AddDadJokesApiClient(httpClient { var host configuration[DadJokesClient:host]; httpClient.BaseAddress new(host); httpClient.AddDadJokesHeaders(host, configuration[DADJOKES_TOKEN]);}); var app builder.Build(); app.MapGet(/, async TaskJoke (IDadJokesApiClient client) { var jokeResponse await client.GetRandomJokeAsync();return jokeResponse.Body.First();}); app.Run();复制代码让我们运行它并欣赏本文最后一个笑话{ punchline: And its really taken off, setup: So I invested in a hot air balloon company..., type: air}复制代码优点➕基于众所周知的规范。有丰富的工具和活跃的社区支持。完全自动化新 SDK 可以作为 CI/CD 流程的一部分在每次 OpenAPI 规范有变化时生成。可以生成多种语言的 SDK。由于可以看到工具链生成的代码所以相对来说比较容易排除故障。缺点➖如果不符合 OpenAPI 规范就无法使用。难以定制和控制生成的 API 客户端的契约。感兴趣的读者还可以了解下AutoRest、Visual Studio Connected Services。选择合适的方法在这篇文章中我们学习了三种不同的构建 SDK 客户端的方法。简单来说可以遵循以下规则选用正确的方法我是一个简单的人。我希望完全控制我的 HTTP 客户端集成。使用手动方法。我是个大忙人但我仍然希望有部分控制权。使用声明式方法。我是个懒人。最好能帮我做。使用自动化方法。决策图如下总结在这篇文章中我们回顾了开发 HTTP 客户端 SDK 的不同方式。请根据具体的用例和需求选择正确的方法希望这篇文章能让你有一个大概的了解使你在设计客户端 SDK 时能做出最好的设计决策。感谢阅读。作者简介Oleksii Nikiforov 是 EPAM Systems 的高级软件工程师和团队负责人。他拥有应用数学学士学位和信息技术硕士学位从事软件开发已有 6 年多热衷于.NET、分布式系统和生产效率是N1博客的作者。
http://www.zqtcl.cn/news/528275/

相关文章:

  • 网站建设费用兴田德润团队西宁网站策划公司
  • 手机价格网站建设用别人备案域名做违法网站
  • 成都武侯区建设厅官方网站石家庄住房和城乡建设部网站
  • 前端做网站的步骤酉阳网站建设
  • 湖北省住房与建设厅网站php做网站访问记录
  • 做网站的公司没有技术吉林北京网站建设
  • 产品设计培训机构哪家好贵州整站优化seo平台
  • 天津网站制作推广wordpress 果酱
  • 写给初学网站开发们的一封信企业网站建设 ppt
  • 做装修网站多少钱做网站百度一下
  • 用asp做网站的可行性分析9免费建网站
  • 网站域名注册商查询徐州集团网站建设报价
  • 句容网站设计公司做网站充值犯法吗
  • 网站建设所用系统网站备案目的
  • 苏州做网站优化公司哪家好网站的大小
  • 四川省住房和城乡建设厅官方网站网站建设图标图片
  • 做影视网站侵权吗评论凡科网站建设怎么样
  • 建设个人网站流程建设游戏网站需要哪些设备
  • 四字母net做网站怎么样河南做网站优化
  • 怎样做网站快照网站当前位置怎么做
  • 网站模板移植现在c 做网站用什么框架
  • 国内专业的室内设计网站盐城网站开发代理商
  • 外贸网站建设 评价wordpress 函数调用
  • 广告支持模式的网站二级域名做网站域名
  • 空间 两个网站购物网站建设图标大全
  • 17.zwd一起做网站广州网站制作费用
  • 如何选择网站建设公司网站开发公司vue框架
  • 网站建设设计外包公司360个人网站建设
  • 什么网站专做店铺公司注销的网站备案
  • 不属于c2c网站的是带货视频怎么制作教程