• 使用.net中的API网关模式封装微服务


    在本文中,我们将了解如何使用API网关模式来封装微服务并抽象出底层实现细节,从而允许使用者拥有进入我们系统的一致入口点。

    为了构建和测试我们的应用程序,我们需要:

    1.Visual Studio 2019

    2..NET Core 5 SDK

    由于微服务是一个相当复杂的主题,在我们进入下一节的代码之前,让我们花点时间解释一下基础知识。

    微服务是一种架构风格,因此这种风格的实现可能会有很大的差异,并且经常是一个备受争议的话题。然而,大多数专家认为微服务具有以下属性:

    • 松散耦合
    • 容易维护
    • 独立部署
    • 可测试
    • 围绕业务能力组织

    庞然大物 vs 微服务

    让我们考虑下面的图表来比较庞然大物和微服务架构:

    我们大多数人都熟悉“庞然大物”体系结构,其中单个应用程序(通常包含多个逻辑“层”,如UI/业务/数据)作为单个流程部署到一个或多个服务器上。

    微服务体系结构试图将应用程序分解为更小的部分,并独立部署它们。分解应用程序的过程是一个复杂而重要的过程,超出了本文的范围,因此在这里推荐一些关于领域驱动设计(DDD)的研究。

    描述庞然大物和微服务体系结构之间的区别本身就是一个主题,由于我们在前面已经谈到了微服务的一些好处,所以这里就不做太多的详细讨论了。就本文而言,我们想要关注的主要好处是独立性。也就是说,我们将看到改变一个微服务是如何不会使整个应用程序崩溃的,因为其他微服务甚至不需要关心这个变化。这与庞然大物架构有很大的不同,在庞然大物架构中,任何微小的更改都需要关闭并更新整个应用程序。

    分解我们的庞然大物

    我们的示例庞然大物应用程序,解决方案如下:

    我们可以看到它是一个简单的ASP.NET Core API,为Authors和Books分别提供一个控制器。

    让我们按下CTRL+F5在浏览器中运行应用程序,它将调用" /books ":

    我们可以看到它返回了一个书单。

    让我们把浏览器中的URL改为/authors:

    创建AuthorsService

    首先,让我们通过添加一个新的ASP.NET Core API来创建AuthorsService:

    现在,我们可以进行一些重构,将相关代码从提取到新的AuthorsService中。

    让我们复制:

    1.Controllers文件夹中的AuthorsController

    2.Models文件夹中的Author

    3.Data文件夹中的Repository

    我们应该以以下结构结束:

    接下来,我们将进行一些调整以启动并运行AuthorsService。

    首先,让我们在Startup.cs中的ConfigureServices方法中添加以下代码:

    services.AddSingleton<Repository>();

    接下来,让我们删除Repository中对Book的引用,最后得到:

    复制代码
    public class Repository
    {
        private IEnumerable<Author> _authors { get; set; }
        public Repository()
        {
            _authors = new[]
            {
                new Author
                {
                    AuthorId = 1,
                    Name = "John Doe"
                },
                new Author
                {
                    AuthorId = 2,
                    Name = "Jane Smith"
                }
            };
        }
        public IEnumerable<Author> GetAuthors() => _authors;
    }
    复制代码

    现在,我们可以运行新的AuthorsService,并将URL指向“/authors”路径:

    太棒了!我们已经启动并运行了作者微服务。

    创建BooksService

    现在,让我们按照上面完全相同的步骤,将相关的Books代码从这个庞然大物提取到一个新的BooksService API中。我们将在这里再次重复所有的步骤,因为这应该是不言而喻的。

    让我们运行这个新服务,并将URL指向“/books”路径:

    现在,我们的Books微服务已经启动并运行。

    现在,我们可以在两个不同的服务器上独立部署这两个微服务,并公开它们使用。它们没有以任何方式耦合在一起。

    但是在下一节中,我们将讨论如何使用API网关模式这种方法解决一些问题。

    API网关模式

    如果有人想要使用我们的庞然大物API,这非常简单,因为只有一个主机需要处理,例如“https://ourmonolithapi.ourcompany.com”

    然而,现在我们已经把这个庞然大物提取成两个独立的微服务,这变得更加困难,因为消费者需要与多个api交互:

    出现的问题包括:

    1.每个服务都在哪里?(发现)

    2.这些服务使用相同的协议吗?(复杂性)

    3.我需要多少次往返才能呈现包含Books和Authors的页面?(性能)

    API网关模式有哪些帮助

    这就是API网关模式的作用所在,它通过坐在微服务的“前面”,将消费者与所有这些问题隔离开来:

    现在回到我们之前的问题:

    每个服务都在哪里?回答:消费者不在乎。它只处理API网关,然后API网关代表消费者与服务进行交互

    这些服务使用相同的协议吗?回答:消费者也不在乎。如果微服务使用不同的协议(例如,如果我们想将BooksService改为使用gRPC而不是HTTP), API网关就有责任在这些协议之间进行映射。

    我需要多少次往返才能使这个页面同时包含Books和Authors?答:API网关可以为消费者“聚合”这些调用。这是特别重要的,因为我们不能控制用户的网络(他们可能在一个缓慢的连接上),但是,我们可以控制我们的内部网络。因此,通过将API网关和微服务紧密结合在一起,我们可以最大化网络效率。

    还有一个类似的模式值得一提,称为“BFF”模式。不,这并不意味着永远是最好的朋友(best friends forever),而是“后端为前端”(Backend-for-frontend)。这个模式与API网关非常相似,但是它涉及到为每个“前端”创建一个API网关。

    这张图说明了我们如何为我们的用例实现BFF模式:

    在这种情况下,每个客户端都有自己的BFF / API网关,其功能可以为特定的客户端量身定制。例如,也许web应用程序需要一些搜索引擎优化功能,而移动应用程序并不关心。这允许移动和web团队自主操作,并拥有自己的数据层。

    然而,在本文中,我们只关注单个消费者的单个API网关。

    我们如何实现API网关模式?

    有很多方法可以实现API网关模式,包括使用现成的软件。最终的选择将取决于API网关所需的特性。

    我们可能需要的一些常见功能包括:

    1.身份验证

    2.限制速度

    3.分析

    4.日志记录

    5.文档

    Traefik、Kong和Azure API Management等服务可以提供这些特性的全部或部分,因此,根据你的用例需要什么,有必要仔细阅读它们。

    然而,出于本文的目的,我们将排除这些特性,而将重点放在最基本的功能上,即消费者和微服务之间的一个简单的基于http的代理。为了实现这一点,我们可以很容易地自己用ASP.NET Core来实现。

    添加我们的API网关

    因为我们已经在我们的解决方案中有了庞然大物API,我们计划使用ASP.NET Core作为我们的API网关,我们可以简单地将它转换成我们想要的。

    首先,让我们删除“Controllers”、“Data”和“Models”文件夹,因为我们不再需要它们了。

    接下来,让我们在Startup中向ConfigureServices()添加以下一行:

    services.AddHttpClient();

    这样我们就可以通过HTTP客户端调用新的微服务。

    接下来,让我们添加一个名为ProxyController的新控制器:

    复制代码
    [Route("[action]")]
    [ApiController]
    public class ProxyController : ControllerBase
    {
        private readonly HttpClient _httpClient;
        public ProxyController(IHttpClientFactory httpClientFactory)
        {
            _httpClient = httpClientFactory.CreateClient();
        }
        [HttpGet]
        public async Task<IActionResult> Books()
        => await ProxyTo("https://localhost:44388/books");
        [HttpGet]
        public async Task<IActionResult> Authors()
        => await ProxyTo("https://localhost:44307/authors");
        private async Task<ContentResult> ProxyTo(string url)
        => Content(await _httpClient.GetStringAsync(url));
    }
    复制代码

    代码应该是相当不言自明的,但本质上我们使用HttpClient来调用我们的新微服务并直接返回响应。

    让我们在解决方案中构建并运行我们所有的三个项目,我们应该有:

    https://localhost: 44307(Authors)

    https://localhost: 44388(Books)

    https://localhost: 5001 (API网关)

    运行完所有程序后,让我们打开浏览器https://localhost:5001/books

    同样,让我们导航到https://localhost:5001/authors:

    我们现在有了一个功能正常的API网关,可以将请求代理到我们的两个微服务!

    在下一节中,让我们添加API网关的一个简单消费者。

    添加一个简单的消费者

    现在我们有了一个API网关,让我们来看看如何添加一个简单的web页面,它可以使用我们的API。

    在此之前,我们需要在API网关中启用CORS,以便能够发出跨域请求。

    让我们打开Startup.cs并修改ConfigureServices():

    复制代码
    services.AddCors(options =>
    {
      options.AddDefaultPolicy(builder =>
      {
        builder.AllowAnyOrigin();
      });
    });
    复制代码

    出于测试目的,我们允许任何来源的CORS。但是对于生产应用程序,我们需要更严格的CORS策略。

    接下来,让我们将CORS中间件添加到ASP.NET Core管道中的Configure()方法:

    app.UseCors();

    让我们变异并运行我们的应用程序,以部署新的更改。

    接下来,让我们创建一个非常简单的HTML页面:

    复制代码
    <html>
    <head>
    </head>
    <body>
        <button onclick="callAPI('books')">Get Books</button>
        <button onclick="callAPI('authors')">Get Authors</button><script type="text/javascript">
        function callAPI(path) {
            let request = new XMLHttpRequest();
            request.open("GET", "https://localhost:5001/" + path);
            request.send();
            request.onload = () => {
                if (request.status === 200) {
                    alert(request.response);
                } else {
                    alert(`Error: ${request.status} ${request.statusText}`);
                }
            }
        }
    </script>
    </body>
    </html>
    复制代码

    这里我们有几个按钮,当点击时将调用我们的API网关并通知结果。

    让我们在浏览器中打开HTML页面,点击“Get Books”按钮,我们看到一个浏览器弹出:

    让我们点击“Get Authors”按钮:

    我们看到消费者能够调用我们的API网关,而API网关又能够将这些请求代理到相关的微服务。

    在下一节中,让我们看看如何更改我们的一个微服务,这将突出微服务API网关模式的好处之一。

    改变Microservice

    我们在前面讨论了微服务应该如何独立部署,以及更改一个微服务不需要关闭整个应用程序(在本例中,“应用程序”就是API网关)。

    我们可以通过改变“Authors”微服务来证明这一理论。

    首先,让我们“关闭”Authors的微服务,停止IIS Express中的站点:

    如果我们再次点击“Get Authors”按钮,我们会看到一个错误:

    然而,如果我们点击“Get Books”按钮:

    正如预期的那样,它仍然返回一个结果。

    现在,我们将对Authors微服务进行一些更改。

    改变Authors的微服务

    首先,让我们为Author类添加一个新属性:

    public string Country { get; set; }

    接下来,让我们更新我们的Repository,以返回我们的新字段:

    复制代码
    _authors = new[]
    {
      new Author
      {
        AuthorId = 1,
        Name = "John Doe",
        Country = "Australia"
      },
      new Author
      {
        AuthorId = 2,
        Name = "Jane Smith",
        Country = "United States"
      }
    };
    复制代码

    这是一个微不足道的更改,但关键是,更改可以是任何东西:来自新数据库的新字段、升级包,甚至用不同的编程语言重写整个应用程序。只要遵守了微服务和API网关之间的契约(例如没有破坏性的更改),就不需要发生任何其他事情。

    让我们再次构建并运行我们的Authors服务,然后点击“Get Authors”按钮:

    我们看到我们的新变化正在传递给消费者。

    值得在此驻足片刻,看看我们取得了哪些成就:

    1.我们创建了一个消费者,它通过一个应用程序(API网关)与两个微服务交互。

    2.我们关闭了其中一个微服务并进行了更新

    3.另一个微服务能够继续提供功能

    考虑一下我们的用户是否功能更丰富,例如,列出了所有的Book。如果该特性不需要任何Author功能,则可以继续为用户提供该特性,甚至对作者进行更新。

    这是非常强大的,因为它允许“优雅”地降低某些功能,同时保留其他功能。我们甚至可以为此向API网关添加更多特性,例如,检测下游服务的中断并返回缓存的数据,或利用备份功能。关键是,我们的后端消费者通过API网关与后台的任何更改隔离开来。

    结论

    在本文中,我们简要介绍了微服务和API网关模式背后的理论,并创建了一个非常简单的设置,演示了一些关键概念。

    尽管我们的实现非常基本,但重要的是我们所设置的可能性。我们能够继续为我们的用户提供应用程序的一些功能,尽管我们正在对其他功能进行一些升级。这在微服务中很常见,它们可能是不同的团队,从事不同的功能和微服务。使用这种方法,升级功能的团队负责更新,而不需要在其他团队之间进行广泛的协调。

    API网关为我们的后端提供了一个很棒的“面子”,可以很容易地控制如何将我们的后端功能服务给我们的消费者,而不必将这些关注点推到下游的每个服务。这意味着实际的服务要灵活得多,只需要关心它们需要交付给API网关的内容。

    下一个逻辑步骤是建立更多的微服务,提高API网关等更多的功能,比如日志,分析和弹性,然而,每一个点本质上是一个新课题。

    希望你喜欢这篇文章。编码快乐!

    原文链接:https://code-maze.com/api-gateway-pattern-dotnet-encapsulate-microservices/

    出处:https://www.cnblogs.com/hhhnicvscs/p/14306371.html

    您的资助是我最大的动力!
    金额随意,欢迎来赏!
    款后有任何问题请给我留言。

    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的推荐按钮。
    如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的关注我。(●'◡'●)

    如果你觉得本篇文章对你有所帮助,请给予我更多的鼓励,求打             付款后有任何问题请给我留言!!!

    因为,我的写作热情也离不开您的肯定支持,感谢您的阅读,我是【Jack_孟】!

  • 相关阅读:
    关于敏捷开发的一些思考。
    【转】浅谈程序猿的职业规划,看你如何决定自己的未来吧。
    Individual Project
    homework_06 围棋程序改进
    homework 08_2 C++11新特性作业之二
    homework_08
    软件工程个人作业——Agile Software Development读后感
    附加题——软件工程之结对编程
    软件工程——PairProject
    软件工程第一次个人项目——词频统计by11061153柴泽华
  • 原文地址:https://www.cnblogs.com/mq0036/p/14328951.html
Copyright © 2020-2023  润新知