{"id":484156,"date":"2026-06-18T15:40:10","date_gmt":"2026-06-18T15:40:10","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=484156"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=484156","title":{"rendered":"Apache Camel \u043f\u043e\u0434 .NET, \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u043e \u043a\u043e\u0441\u0442\u043e\u0447\u043a\u0430\u043c: HTTP-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0431\u0435\u0437 ASP.NET MVC + \u043f\u0430\u0442\u0442\u0435\u0440\u043d Content-Based Router"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cd1\/f97\/0cb\/cd1f970cb2bf7491ea75cb1b7feba7e8.jpg\" alt=\"redb route http chise when\" title=\"redb route http chise when\" width=\"784\" height=\"1168\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/cd1\/f97\/0cb\/cd1f970cb2bf7491ea75cb1b7feba7e8.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cd1\/f97\/0cb\/cd1f970cb2bf7491ea75cb1b7feba7e8.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>redb route http chise when<\/figcaption><\/div>\n<\/figure>\n<p><strong>\u0421\u0435\u0440\u0438\u044f:<\/strong>\u00a0redb ecosystem \/ redb.Route deep-dive<\/p>\n<p>\u0412\u00a0<a href=\"https:\/\/habr.com\/ru\/articles\/1042392\/\" rel=\"noopener noreferrer nofollow\">redb.Route<\/a>\u00a0\u2014 \u043d\u0430\u0448\u0435\u043c ESB \u0432 \u0441\u0442\u0438\u043b\u0435\u00a0<a href=\"https:\/\/camel.apache.org\/\" rel=\"noopener noreferrer nofollow\">Apache Camel<\/a>\u00a0\u043f\u043e\u0434 .NET \u2014 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0432\u0441\u0435\u0433\u0434\u0430 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e:\u00a0<code>From(\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a) \u2192 [\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b] \u2192 To(\u043f\u0440\u0438\u0451\u043c\u043d\u0438\u043a)<\/code>. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0431\u0435\u0440\u0451\u043c\u00a0<strong>\u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438<\/strong>\u00a0\u0438\u00a0<strong>\u043e\u0434\u0438\u043d \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440<\/strong>\u00a0\u0438 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0431\u0430 \u0434\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u0434\u043d\u0430.<\/p>\n<ul>\n<li>\n<p><strong>\u041f\u0430\u0442\u0442\u0435\u0440\u043d:<\/strong>\u00a0<a href=\"https:\/\/www.enterpriseintegrationpatterns.com\/patterns\/messaging\/ContentBasedRouter.html\" rel=\"noopener noreferrer nofollow\">Content-Based Router<\/a>\u00a0\u2014 \u00ab\u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443\u00bb. \u0421\u0430\u043c\u044b\u0439 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0438\u0437 routing-\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432\u00a0<a href=\"https:\/\/www.enterpriseintegrationpatterns.com\/\" rel=\"noopener noreferrer nofollow\">\u0425\u043e\u043f\u0435 \u0438 \u0412\u0443\u043b\u044c\u0444\u0430<\/a>: \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u0440\u0435\u0448\u0438\u0442\u044c, \u043a\u0443\u0434\u0430 \u043e\u043d\u043e \u043f\u043e\u0435\u0434\u0435\u0442 \u0434\u0430\u043b\u044c\u0448\u0435. \u0412 DSL \u044d\u0442\u043e\u00a0<code>.Choice().When(...).Otherwise()<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440:<\/strong>\u00a0<code>redb.Route.Http<\/code>\u00a0\u2014 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 HTTP\/HTTPS. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u044d\u0442\u043e\u00a0<strong>\u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440<\/strong>\u00a0(HTTP-\u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430\u00a0<code>HttpClient<\/code>), \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u2014\u00a0<strong>\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440<\/strong>\u00a0(\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430\u00a0<a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/servers\/kestrel\" rel=\"noopener noreferrer nofollow\">Kestrel<\/a>). \u0411\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432, \u0431\u0435\u0437\u00a0<code>[ApiController]<\/code>, \u0431\u0435\u0437 middleware-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u043f\u0438\u0448\u0435\u0442\u0435 \u0440\u0443\u043a\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0438 \u0431\u043e\u043b\u044c\u0448\u0430\u044f. \u0415\u0441\u043b\u0438 \u0432\u044b \u0436\u0434\u0451\u0442\u0435 \u00abhello world \u0437\u0430 5 \u0441\u0442\u0440\u043e\u043a\u00bb \u2014 \u043e\u043d \u0431\u0443\u0434\u0435\u0442, \u043d\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u043c\u044b \u0432\u043b\u0435\u0437\u0430\u0435\u043c \u0432 \u0442\u043e, \u043a\u0430\u043a \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0432\u043d\u0443\u0442\u0440\u0438: \u043a\u0430\u043a \u043e\u0434\u0438\u043d Kestrel \u0448\u0430\u0440\u0438\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c\u0438, \u043a\u0430\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432\u00a0<code>Exchange<\/code>\u00a0\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 CORS \u043d\u0430 \u043e\u0431\u0449\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043e \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433\u043e\u043c \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0432 \u043a\u043e\u0434\u0435 \u043d\u0435\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e\u00a0<code>app.UseCors()<\/code>.<\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d \u043f\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c\u00a0<code>redb.Route\/src\/redb.Route.Http<\/code>, \u0432\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u2014 \u0438\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e\u00a0<code>redb.Route.Demo<\/code>.<\/p>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 0. \u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u0451 \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f<\/h3>\n<p>\u0412\u043e\u0437\u044c\u043c\u0451\u043c \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0451\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443: HTTP-\u0448\u043b\u044e\u0437. \u0421\u043d\u0430\u0440\u0443\u0436\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u00a0<code>POST \/api\/demo<\/code>, \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u044b:<\/p>\n<ol>\n<li>\n<p>\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0442\u0435\u043b\u043e,<\/p>\n<\/li>\n<li>\n<p><strong>\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a\u00a0<\/strong><code><strong>mode<\/strong><\/code>\u00a0\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0435\u0433\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0435\u0442\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u2014 \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c Content-Based Router;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u0432\u0435\u0447\u0430\u0435\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0442\u0435\u043c \u0436\u0435 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c (request\/reply).<\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u043e\u0442 \u0441\u043a\u0435\u043b\u0435\u0442 (\u043f\u043e\u043b\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0432 \u043a\u043e\u043d\u0446\u0435),\u00a0<code>redb.Route.Demo\/Routes\/MainPipelineRoutes.cs<\/code>:<\/p>\n<pre><code>From(\"http:0.0.0.0:5088\/api\/demo?inOut=true\")    .RouteId(\"demo-http-entry\")    .ConvertBody&lt;string&gt;()    .Choice()        .When(e =&gt; GetHeader(e, \"mode\") == \"full\")            .SetHeader(\"stamp.dsl\", \"full-branch\")        .When(e =&gt; GetHeader(e, \"mode\") == \"short\")            .SetHeader(\"stamp.dsl\", \"short-branch\")        .Otherwise()            .SetHeader(\"mode\", \"default\")            .SetHeader(\"stamp.dsl\", \"default-branch\")    .EndChoice()    .SetHeader(\"Content-Type\", \"application\/json\")    .SetBody(e =&gt; BuildResponse(e));<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0434\u0438\u043d\u00a0<code>From<\/code>\u00a0\u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 5088, \u043e\u0434\u0438\u043d\u00a0<code>.Choice()<\/code>\u00a0\u0440\u0435\u0448\u0430\u0435\u0442 \u0441\u0443\u0434\u044c\u0431\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u0434\u0438\u043d\u00a0<code>.SetBody(...)<\/code>\u00a0\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043e\u0442\u0432\u0435\u0442. \u0414\u0430\u043b\u044c\u0448\u0435 \u2014 \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 1. Content-Based Router \u2014 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u0447\u0435\u0441\u0442\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440<\/h3>\n<h4>\u0427\u0442\u043e \u044d\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0442\u0430\u043a\u043e\u0435<\/h4>\n<p>Content-Based Router \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441:\u00a0<em>\u00ab\u043a\u0443\u0434\u0430 \u0434\u0430\u043b\u044c\u0448\u0435?\u00bb<\/em>\u00a0\u2014 \u0433\u043b\u044f\u0434\u044f \u0432 \u0441\u0430\u043c\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0430 \u043d\u0435 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u044e\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e. \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u043a\u043d\u0438\u0433\u0438: \u0437\u0430\u043a\u0430\u0437\u044b \u0441\u00a0<code>region=EU<\/code>\u00a0\u0435\u0434\u0443\u0442 \u0432 \u043e\u0434\u0438\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a,\u00a0<code>region=US<\/code>\u00a0\u2014 \u0432 \u0434\u0440\u0443\u0433\u043e\u0439, \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u2014 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.<\/p>\n<p>\u0412 redb.Route \u044d\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u00a0<code>ChoiceProcessor<\/code>\u00a0(\u0441\u043c.\u00a0<code>redb.Route\/src\/redb.Route\/Processors\/ChoiceProcessor.cs<\/code>), \u0430 \u0432 DSL \u2014 \u0431\u043b\u043e\u043a\u00a0<code>.Choice()<\/code>:<\/p>\n<pre><code>.Choice()    .When(&lt;\u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442&gt;)   \/\/ \u0432\u0435\u0442\u043a\u0430 1        ...processors...    .When(&lt;\u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442&gt;)   \/\/ \u0432\u0435\u0442\u043a\u0430 2        ...processors...    .Otherwise()        \/\/ \u0432\u0435\u0442\u043a\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430)        ...processors....EndChoice()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0430 \u0440\u043e\u0432\u043d\u043e \u043a\u0430\u043a \u0432\u00a0<code>switch<\/code>: \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442\u0441\u044f\u00a0<strong>\u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437<\/strong>, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f\u00a0<strong>\u043f\u0435\u0440\u0432\u0430\u044f<\/strong>\u00a0\u0432\u0435\u0442\u043a\u0430, \u0447\u0435\u0439 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442 \u0432\u0435\u0440\u043d\u0443\u043b\u00a0<code>true<\/code>, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u043d\u0438 \u043e\u0434\u043d\u0430 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0438 \u0435\u0441\u0442\u044c\u00a0<code>.Otherwise()<\/code>\u00a0\u2014 \u0438\u0434\u0451\u0442 \u043e\u043d\u0430; \u0435\u0441\u043b\u0438\u00a0<code>.Otherwise()<\/code>\u00a0\u043d\u0435\u0442 \u2014 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0431\u043b\u043e\u043a \u043d\u0430\u0441\u043a\u0432\u043e\u0437\u044c \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/p>\n<h4>\u0414\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0437\u0430\u0434\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442<\/h4>\n<p><strong>1. \u041b\u044f\u043c\u0431\u0434\u0430<\/strong>\u00a0\u2014 \u043a\u043e\u0433\u0434\u0430 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u044c \u043a\u043e\u0434\u043e\u043c:<\/p>\n<pre><code>.Choice()    .When(e =&gt; GetHeader(e, \"mode\") == \"full\")  ...    .When(e =&gt; GetHeader(e, \"mode\") == \"short\") ...    .Otherwise() ....EndChoice()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>2. Fluent-\u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442\u044b \u043f\u043e\u0432\u0435\u0440\u0445 expression-\u0434\u0432\u0438\u0436\u043a\u0430<\/strong>\u00a0\u2014 \u043a\u043e\u0433\u0434\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438. \u0418\u0437\u00a0<code>redb.Route.Demo\/Routes\/DataObservabilityRoutes.cs<\/code>:<\/p>\n<pre><code>.Choice()    .When(Header(\"amount\").isGreaterThanOrEqualTo(1000).Matches, w =&gt; w        .SetHeader(\"tier\", \"gold\"))    .When(Header(\"amount\").isBetween(500, 999).Matches, w =&gt; w        .SetHeader(\"tier\", \"silver\"))    .When(Header(\"amount\").isLessThan(500).Matches, w =&gt; w        .SetHeader(\"tier\", \"bronze\"))    .Otherwise(o =&gt; o        .SetHeader(\"tier\", \"unknown\"))<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>Header(\"amount\").isBetween(500, 999)<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043d\u0435 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435, \u0430 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439\u00a0<code>IPredicate<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u0435\u043b\u0435\u0433\u0430\u0442. \u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u2014 \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0439 expression-\u0434\u0432\u0438\u0436\u043e\u043a \u0441\u0435\u0440\u0438\u0438 (<code>Tokenizer \u2192 Parser \u2192 AST \u2192 System.Linq.Expressions \u2192 IL<\/code>), \u043d\u043e \u044d\u0442\u043e \u0442\u0435\u043c\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u0441 HTTP<\/h4>\n<p>Content-Based Router \u0438 HTTP-\u0448\u043b\u044e\u0437 \u2014 \u043f\u0430\u0440\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0430\u044f \u0434\u0440\u0443\u0433 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0430. \u041d\u0430 \u0432\u0445\u043e\u0434\u0435 HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438\u00a0<code>Exchange<\/code>\u00a0(\u043e\u0431 \u044d\u0442\u043e\u043c \u043d\u0438\u0436\u0435): \u043c\u0435\u0442\u043e\u0434, \u043f\u0443\u0442\u044c, query-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, route-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0432\u0441\u0435 HTTP-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438. \u041b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043d\u0438\u0445 \u2014 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0434\u043b\u044f\u00a0<code>.When(...)<\/code>:<\/p>\n<pre><code>.Choice()    .When(e =&gt; GetHeader(e, \"redbHttp.Method\") == \"DELETE\")  ... \/\/ \u043f\u043e \u043c\u0435\u0442\u043e\u0434\u0443    .When(e =&gt; GetHeader(e, \"X-Tenant\") == \"acme\")           ... \/\/ \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443    .When(e =&gt; GetHeader(e, \"redbHttp.QueryParam.debug\") == \"1\") ... \/\/ \u043f\u043e query.EndChoice()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440 \u043d\u0435 \u043b\u0435\u0437\u0435\u0442 \u0432 HTTP \u0441\u0430\u043c \u2014 \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0443\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u00a0<code>Exchange<\/code>. \u042d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0441\u043c\u044b\u0441\u043b \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430: \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043e \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u043b\u0438.<\/p>\n<h4>\u041f\u0440\u044f\u043c\u043e \u0438\u0437 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0430<\/h4>\n<p>\u0412\u043e\u0442\u00a0<strong>\u0431\u043e\u0435\u0432\u043e\u0439<\/strong>\u00a0\u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0438\u0437 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d-\u0441\u0438\u0441\u0442\u0435\u043c\u044b TsUM (\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438), \u043e\u0434\u0438\u043d-\u0432-\u043e\u0434\u0438\u043d. HTTP-\u0432\u0445\u043e\u0434 + Content-Based Router \u043f\u043e \u043c\u0435\u0442\u043e\u0434\u0443 \u2014 GET \u0438 POST \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u043f\u0443\u0442\u0438 \u0440\u0430\u0437\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0440\u0430\u0437\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438:<\/p>\n<pre><code>From(\"http:0.0.0.0:5090\/api\/tsum\/user-filters?inOut=true&amp;cors=true&amp;corsOrigins=*\")    .RouteId(\"tsum-api-user-filters\")    .Process(Auth.ProcessAsync)                 \/\/ JWT-\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440    .ConvertBody&lt;string&gt;()    .Choice()        .When(e =&gt; e.In.Headers.TryGetValue(\"redbHttp.Method\", out var m) &amp;&amp; m?.ToString() == \"POST\")            .ProcessWithRedb((redb, exchange, ct) =&gt; HandlePost(redb, exchange))        .Otherwise()            .ProcessWithRedb((redb, exchange, ct) =&gt; HandleGet(redb, exchange))    .EndChoice();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0438\u0434\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u0432\u0441\u0451, \u043e \u0447\u0451\u043c \u043f\u043e\u0439\u0434\u0451\u0442 \u0440\u0435\u0447\u044c \u0434\u0430\u043b\u044c\u0448\u0435: HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 5090 (<code>inOut=true<\/code>,\u00a0<code>cors=true&amp;corsOrigins=*<\/code>), Content-Based Router \u043f\u043e\u00a0<code>redbHttp.Method<\/code>, \u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043a\u0430\u043a\u00a0<strong>\u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440<\/strong>\u00a0\u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u2014 \u043d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0<code>[Authorize]<\/code>-\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432. \u0414\u0430\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c, \u043a\u0430\u043a \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0443\u0441\u043e\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u043d\u0443\u0442\u0440\u0438.<\/p>\n<hr\/>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a72\/e0c\/fd4\/a72e0cfd4a17f9d67563ba36d665ff79.png\" alt=\"tsak \" title=\"tsak \" width=\"1280\" height=\"961\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a72\/e0c\/fd4\/a72e0cfd4a17f9d67563ba36d665ff79.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a72\/e0c\/fd4\/a72e0cfd4a17f9d67563ba36d665ff79.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>tsak <\/figcaption><\/div>\n<\/figure>\n<h3>\u0427\u0430\u0441\u0442\u044c 2. HTTP-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440: \u0441 \u0432\u044b\u0441\u043e\u0442\u044b \u043f\u0442\u0438\u0447\u044c\u0435\u0433\u043e \u043f\u043e\u043b\u0451\u0442\u0430<\/h3>\n<p>\u041e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 scheme\u00a0<code>http<\/code>\/<code>https<\/code>\u00a0\u0434\u0430\u0451\u0442 \u0434\u0432\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0440\u043e\u043b\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0441\u0442\u043e\u0438\u0442 \u043e\u043d \u0432\u00a0<code>From(...)<\/code>\u00a0\u0438\u043b\u0438 \u0432\u00a0<code>To(...)<\/code>:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0420\u043e\u043b\u044c<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041a\u043b\u0430\u0441\u0441<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041d\u0430 \u0447\u0451\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440<\/strong>\u00a0(<code>From<\/code>)<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>HttpConsumer<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">Kestrel<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440<\/strong>\u00a0(<code>To<\/code>)<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>HttpProducer<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>HttpClient<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0428\u043b\u0451\u0442 \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0430\u0434\u0440\u0435\u0441<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 DSL \u2014 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u044b\u00a0<code>Http<\/code>\u00a0\u0438\u00a0<code>Https<\/code>\u00a0(<code>redb.Route.Http\/Fluent\/HttpDsl.cs<\/code>):<\/p>\n<pre><code>\/\/ \u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u2014 \u0441\u043b\u0443\u0448\u0430\u0435\u043c \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435.From(Http.Listen(\"\/webhook\").Port(8080).Cors(\"https:\/\/app.example.com\").InOut())\/\/ \u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 \u2014 \u0448\u043b\u0451\u043c \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435.To(Http.Post(\"api.example.com\/orders\").BearerAuth().Timeout(5000))<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041b\u0438\u0431\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0439 URI \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e (\u0431\u0438\u043b\u0434\u0435\u0440 \u0440\u043e\u0432\u043d\u043e \u0432 \u043d\u0435\u0451 \u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f):<\/p>\n<pre><code>.From(\"http:0.0.0.0:8080\/webhook?cors=true&amp;corsOrigins=https:\/\/app.example.com&amp;inOut=true\").To(\"http:api.example.com\/orders?method=POST&amp;timeout=5000\")<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041c\u0435\u0442\u043e\u0434\u044b HTTP: \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0441\u043b\u0443\u0448\u0430\u0435\u0442, \u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 \u0448\u043b\u0451\u0442<\/h4>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b (GET\/POST\/PUT\/\u2026) \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u0440\u043e\u043b\u0435\u0439 \u2014 \u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e. \u0421\u043d\u0430\u0447\u0430\u043b\u0430\u00a0<strong>\u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440<\/strong>\u00a0(<code>To<\/code>) \u2014 \u043a\u0430\u043a\u043e\u0439 \u043c\u0435\u0442\u043e\u0434\u00a0<strong>\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c<\/strong>:<\/p>\n<pre><code>\/\/ fluent \u2014 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0444\u0430\u0431\u0440\u0438\u0447\u043d\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c:.To(Http.Get(\"api.example.com\/users\"))           \/\/ GET.To(Http.Post(\"api.example.com\/users\"))          \/\/ POST.To(Http.Put(\"api.example.com\/users\/42\"))        \/\/ PUT.To(Http.Delete(\"api.example.com\/users\/42\"))     \/\/ DELETE.To(Http.Patch(\"api.example.com\/users\/42\"))      \/\/ PATCH.To(Http.Head(\"api.example.com\/users\/42\"))       \/\/ HEAD\/\/ \u0442\u043e \u0436\u0435 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 URI (\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u2014 method):.To(\"http:api.example.com\/users?method=POST\")\/\/ \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 \u043b\u0435\u0442\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u043e\u043d \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442 \u0443 \u043e\u043f\u0446\u0438\u0438:.SetHeader(\"redbHttp.Method\", \"PUT\").To(Http.Post(\"api.example.com\/users\/42\"))        \/\/ \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u0439\u0434\u0451\u0442 PUT<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c\u00a0<strong>\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440<\/strong>\u00a0(<code>From<\/code>) \u2014 \u043a\u0430\u043a\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b\u00a0<strong>\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c<\/strong>:<\/p>\n<pre><code>\/\/ \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0412\u0421\u0415 \u043c\u0435\u0442\u043e\u0434\u044b:.From(Http.Listen(\"\/webhook\").Port(8080))\/\/ \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d\u043d\u044b\u0445 (\u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u2192 405 Method Not Allowed):.From(Http.Listen(\"\/webhook\").Port(8080).Methods(\"POST\")).From(Http.Listen(\"\/orders\").Port(8080).Methods(\"POST,PUT\"))\/\/ \u0442\u043e \u0436\u0435 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 URI (\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u2014 methods):.From(\"http:0.0.0.0:8080\/webhook?methods=POST\")\/\/ \u0448\u043e\u0440\u0442\u043a\u0430\u0442: \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0443\u0442\u0438 (\u0434\u043b\u044f \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u0430):.From(\"http:POST:0.0.0.0:8080\/webhook\").From(\"http:GET:\/health\")<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u0445 \u043b\u0435\u0433\u043a\u043e \u043f\u0443\u0442\u0430\u0435\u0442\u0441\u044f:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\n<\/th>\n<th>\n<p align=\"left\">\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 (<code>To<\/code>)<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 (<code>From<\/code>)<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 URI<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>method<\/code>\u00a0(\u0435\u0434. \u0447.)<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>methods<\/code>\u00a0(\u043c\u043d. \u0447., \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0421\u043c\u044b\u0441\u043b<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043a\u0430\u043a\u043e\u0439 \u043c\u0435\u0442\u043e\u0434\u00a0<strong>\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043a\u0430\u043a\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b\u00a0<strong>\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c<\/strong>\u00a0(\u043f\u0443\u0441\u0442\u043e = \u0432\u0441\u0435)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0414\u0435\u0444\u043e\u043b\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>GET<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Override \u043d\u0430 \u043b\u0435\u0442\u0443<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a\u00a0<code>redbHttp.Method<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u2014 (\u0444\u0438\u043b\u044c\u0442\u0440 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u043d)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041f\u0440\u0435\u0444\u0438\u043a\u0441-\u0448\u043e\u0440\u0442\u043a\u0430\u0442 (<code>http:POST:\/...<\/code>) \u2014 \u0447\u0430\u0441\u0442\u043d\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439: \u043e\u043d \u0441\u0442\u0430\u0432\u0438\u0442\u00a0<strong>\u043e\u0431\u0430<\/strong>\u00a0\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0440\u0430\u0437\u0443 (\u0438\u00a0<code>method<\/code>, \u0438\u00a0<code>methods<\/code>), \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u0434\u043d\u0430 \u0438 \u0442\u0430 \u0436\u0435 \u0437\u0430\u043f\u0438\u0441\u044c \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u043e\u043c, \u0438 \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u043e\u043c.<\/p>\n<p>\u0418 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u0451\u043c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430 \u043e\u0434\u0438\u043d \u043f\u0443\u0442\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442\u00a0<strong>\u0440\u0430\u0437\u043d\u044b\u0435<\/strong>\u00a0\u043c\u0435\u0442\u043e\u0434\u044b: \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438 \u0440\u0430\u0437\u0432\u043e\u0434\u0438\u043c Content-Based Router&#8217;\u043e\u043c \u043f\u043e\u00a0<code>redbHttp.Method<\/code>\u00a0(\u044d\u0442\u043e \u0440\u043e\u0432\u043d\u043e \u043f\u0440\u043e\u0434-\u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u0447\u0430\u0441\u0442\u0438 1):<\/p>\n<pre><code>.From(Http.Listen(\"\/api\/tsum\/user-filters\").Port(5090).Methods(\"GET,POST\").Cors(\"*\").InOut())    .Choice()        .When(e =&gt; GetHeader(e, \"redbHttp.Method\") == \"POST\")            .ProcessWithRedb((redb, ex, ct) =&gt; HandlePost(redb, ex))   \/\/ \u0437\u0430\u043f\u0438\u0441\u044c        .Otherwise()            .ProcessWithRedb((redb, ex, ct) =&gt; HandleGet(redb, ex))    \/\/ \u0447\u0442\u0435\u043d\u0438\u0435    .EndChoice();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0431\u0435 \u0440\u043e\u043b\u0438 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u2014 \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441.<\/p>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 3. \u00ab\u0410 \u0433\u0434\u0435 \u0436\u0435 ASP.NET?\u00bb \u2014 \u0435\u0433\u043e \u043d\u0435\u0442, \u0438 \u044d\u0442\u043e \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/h3>\n<p>\u041a\u043e\u0433\u0434\u0430 .NET-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043b\u044b\u0448\u0438\u0442 \u00ab\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440\u00bb, \u043e\u043d \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u00a0<code>WebApplication<\/code>, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b,\u00a0<code>[HttpPost]<\/code>, \u0444\u0438\u043b\u044c\u0442\u0440\u044b, model binding,\u00a0<code>app.UseRouting()<\/code>,\u00a0<code>app.UseCors()<\/code>, DI-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440 middleware.\u00a0<strong>\u0412 HTTP-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0435 redb.Route \u043d\u0438\u0447\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0442.<\/strong>\u00a0\u0415\u0441\u0442\u044c Kestrel \u2014 \u0433\u043e\u043b\u044b\u0439, \u0431\u0435\u0437 MVC-\u043d\u0430\u0434\u0441\u0442\u0440\u043e\u0439\u043a\u0438.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440 (<code>SharedHttpServerManager.StartServer<\/code>, \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043e):<\/p>\n<pre><code>var builder = WebApplication.CreateSlimBuilder();   \/\/ slim \u2014 \u0431\u0435\u0437 MVC, \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432builder.WebHost.ConfigureKestrel(kestrel =&gt;{    kestrel.Listen(IPAddress.Parse(entry.Host), entry.Port, listenOptions =&gt;    {        listenOptions.Protocols = protocols;          \/\/ HTTP\/1, \/2, \/3 \u2014 \u0441\u043c. \u043d\u0438\u0436\u0435        if (entry.Ssl) listenOptions.UseHttps(entry.SslCertPath, entry.SslCertPassword);    });    kestrel.Limits.MaxRequestBodySize = entry.MaxRequestBodySize &gt; 0        ? entry.MaxRequestBodySize : null;});builder.Logging.ClearProviders();var app = builder.Build();\/\/ \u041e\u0414\u0418\u041d catch-all \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u2014 \u0434\u0430\u043b\u044c\u0448\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0441\u0430\u043c\u0438app.Map(\"\/{**path}\", (HttpContext ctx) =&gt; HandleCatchAll(entry, ctx));app.MapGet(\"\/\",    (HttpContext ctx) =&gt; HandleCatchAll(entry, ctx));app.MapPost(\"\/\",   (HttpContext ctx) =&gt; HandleCatchAll(entry, ctx));\/\/ ... PUT\/DELETE\/PATCH\/HEAD\/OPTIONS \u043d\u0430 \"\/\"await app.StartAsync(ct);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f:<\/p>\n<ul>\n<li>\n<p><code><strong>WebApplication.CreateSlimBuilder()<\/strong><\/code>, \u0430 \u043d\u0435\u00a0<code>CreateBuilder()<\/code>.\u00a0<a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/minimal-apis\/webapplication\" rel=\"noopener noreferrer nofollow\">Slim-\u0431\u0438\u043b\u0434\u0435\u0440<\/a>\u00a0\u043d\u0435 \u0442\u0430\u0449\u0438\u0442 MVC, Razor, \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> \u0438 \u043f\u0440\u043e\u0447\u0443\u044e \u043e\u0431\u0432\u044f\u0437\u043a\u0443 \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e Kestrel.<\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u043e\u0432\u043d\u043e \u043e\u0434\u0438\u043d catch-all \u043c\u0430\u0440\u0448\u0440\u0443\u0442<\/strong>\u00a0<code>\/{**path}<\/code>. <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a>-\u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442\u044c\u00a0<em>\u0432\u0441\u0451<\/em>\u00a0\u0438 \u043e\u0442\u0434\u0430\u0442\u044c \u0432 \u043d\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u00a0<code>HandleCatchAll<\/code>. \u041d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><code><strong>builder.Logging.ClearProviders()<\/strong><\/code>\u00a0\u2014 \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u043b\u0447\u0438\u0442 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0445\u043e\u0441\u0442\u0430; \u043b\u043e\u0433\u0438 \u0438\u0434\u0443\u0442 \u0447\u0435\u0440\u0435\u0437 \u043b\u043e\u0433\u0433\u0435\u0440 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e redb.Route \u2014 \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a, \u0438 HTTP \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u2014 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442, \u043a\u0430\u043a Kafka \u0438\u043b\u0438 RabbitMQ. \u041c\u0430\u0440\u0448\u0440\u0443\u0442 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e \u0437\u0430 \u043d\u0438\u043c Kestrel: \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u00a0<code>Exchange<\/code>. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> \u043d\u0430\u0432\u044f\u0437\u0430\u043b\u0438 \u0431\u044b \u0441\u0432\u043e\u044e \u043c\u043e\u0434\u0435\u043b\u044c (\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, model binding,\u00a0<code>ActionResult<\/code>), \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 DSL-\u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0435 \u043b\u0438\u0448\u043d\u044f\u044f \u0438 \u0447\u0443\u0436\u0435\u0440\u043e\u0434\u043d\u0430\u044f.<\/p>\n<h4>\u041e\u0434\u0438\u043d Kestrel \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u0430 \u043d\u0435 \u043d\u0430 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u2014 \u0438 Tsak \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442<\/h4>\n<p>\u0427\u0430\u0441\u0442\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441:\u00a0<em>\u00ab\u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f \u043d\u0430 ASP.NET\/Kestrel (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 Tsak-\u0432\u043e\u0440\u043a\u0435\u0440\u0435), \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438\u043b\u0438 \u043f\u043b\u043e\u0434\u0438\u0442 \u043d\u043e\u0432\u044b\u0435?\u00bb<\/em><\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0442\u043e, \u0447\u0435\u0433\u043e \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u00a0<strong>\u043d\u0435<\/strong>\u00a0\u0434\u0435\u043b\u0430\u0435\u0442: \u043e\u043d \u043d\u0435 \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0447\u0443\u0436\u043e\u0439 <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a>-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440. \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435\u00a0<code>redb.Route.Http<\/code>\u00a0\u043d\u0435\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0445\u043e\u0441\u0442\u043e\u043c (<code>IApplicationBuilder<\/code>,\u00a0<code>UseEndpoints<\/code>,\u00a0<code>IServer<\/code>\u00a0\u2014 \u043d\u0438\u0447\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0442). \u0421\u0432\u043e\u0439 Kestrel \u043e\u043d \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u0430\u043c, \u0447\u0435\u0440\u0435\u0437\u00a0<code>WebApplication.CreateSlimBuilder()<\/code>.<\/p>\n<p>\u041d\u043e \u00ab\u0441\u0430\u043c \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u00bb \u2260 \u00ab\u043f\u043b\u043e\u0434\u0438\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b\u00bb. \u041a\u043b\u044e\u0447 \u2014 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u00a0<code>SharedHttpServerManager<\/code>\u00a0\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 DI \u043a\u0430\u043a\u00a0<strong>\u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d<\/strong>\u00a0(<code>redb.Route.Http\/Extensions\/ServiceCollectionExtensions.cs<\/code>):<\/p>\n<pre><code>public static IServiceCollection AddRedbRouteHttp(this IServiceCollection services, ...){    services.AddSingleton&lt;SharedHttpServerManager&gt;();   \/\/ \u2190 \u043e\u0434\u0438\u043d \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441    services.AddSingleton(sp =&gt; { var c = new HttpComponent();        c.ServerManager = sp.GetRequiredService&lt;SharedHttpServerManager&gt;(); ... return c; });    services.AddSingleton(sp =&gt; { var c = new HttpsComponent(); ... });    ...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0434\u0438\u043d \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u2014 \u0437\u043d\u0430\u0447\u0438\u0442\u00a0<strong>\u043e\u0434\u0438\u043d \u043f\u0443\u043b Kestrel, \u043e\u0431\u0449\u0438\u0439 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u0432<\/strong>. \u0418 Tsak \u043e\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u044d\u0442\u043e. \u0415\u0433\u043e \u0432\u043e\u0440\u043a\u0435\u0440 \u2014 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0<code>Host.CreateDefaultBuilder<\/code>\u00a0(\u0430\u00a0<strong>\u043d\u0435<\/strong>\u00a0<code>WebApplication<\/code>), \u0443 \u043d\u0435\u0433\u043e\u00a0<strong>\u043d\u0435\u0442 \u0441\u0432\u043e\u0435\u0433\u043e Kestrel<\/strong>. \u0414\u0430\u0436\u0435 REST-\u0430\u0434\u043c\u0438\u043d\u043a\u0430 \u0441\u0430\u043c\u043e\u0433\u043e Tsak (\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u00a0<code>_system<\/code>, \u043f\u043e\u0440\u0442 9090 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e) \u2014 \u044d\u0442\u043e \u043d\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 redb.Route HTTP-\u043c\u0430\u0440\u0448\u0440\u0443\u0442, \u043f\u043e\u0434\u043d\u044f\u0442\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 \u0442\u043e\u0442 \u0436\u0435 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d-\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 (<code>redb.Tsak.Core\/Services\/SystemContextBuilder.cs<\/code>):<\/p>\n<pre><code>\/\/ Tsak \u0441\u0430\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 HTTP-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440...services.AddRedbRouteHttp();   \/\/ redb.Tsak.Core\/Extensions\/ServiceCollectionExtensions.cs\/\/ ...\u0438 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u0432\u043e\u044e \u0430\u0434\u043c\u0438\u043d\u043a\u0443 \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043d\u0430 \u043e\u0431\u0449\u0435\u043c \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0435:var listenUri = $\"http:{host}:{port}\/{{**path}}?host={host}&amp;port={port}&amp;inOut=true\";routeContext.AddRoutes(r =&gt; r.From(listenUri).Process(\/* bridge \u2192 auth \u2192 dispatch *\/));<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u00ab\u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u0437 Kestrel \u0445\u043e\u0441\u0442\u0430\u00bb \u2014 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442,\u00a0<strong>\u0445\u043e\u0441\u0442 (Tsak) \u0441\u0430\u043c \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 Kestrel \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0435\u0433\u043e<\/strong>. \u041b\u044e\u0431\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442, \u043d\u0430\u0446\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u0442\u043e\u0442 \u0436\u0435\u00a0<code>(host, port)<\/code>,\u00a0<strong>\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u043c\u0443<\/strong>\u00a0\u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0430 \u043d\u0435 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0442\u043e\u0440\u043e\u0439. Tsak \u0434\u0430\u0436\u0435 \u0432\u0435\u0448\u0430\u0435\u0442 \u0441\u0432\u043e\u0439\u00a0<code>system-echo<\/code>\u00a0\u043d\u0430 \u043f\u043e\u0440\u0442 \u0430\u0434\u043c\u0438\u043d\u043a\u0438 \u2014 \u0438 \u043e\u043d\u0438 \u043d\u0435 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u0443\u044e\u0442: \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u0438\u0437 \u0447\u0430\u0441\u0442\u0438 4 \u0440\u0430\u0437\u0432\u043e\u0434\u0438\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439\u00a0<code>\/api\/echo<\/code>\u00a0\u0438 catch-all\u00a0<code>{**path}<\/code>\u00a0(\u044d\u0442\u043e \u043f\u0440\u044f\u043c\u043e \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u0432\u00a0<code>SystemContextBuilder<\/code>).<\/p>\n<h4>\u0410 \u0431\u0435\u0437 Tsak \u2014 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0437\u0430\u0432\u043e\u0434\u0438\u0448\u044c \u0441\u0430\u043c<\/h4>\n<p>Tsak \u0442\u0443\u0442 \u043d\u0435 \u043c\u0430\u0433\u0438\u044f: Kestrel\u00a0<strong>\u0432\u0441\u0435\u0433\u0434\u0430<\/strong>\u00a0\u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u00a0<code>SharedHttpServerManager<\/code>, \u0430 Tsak \u2014 \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u043e\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044d\u0442\u043e\u0442 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0438 \u0441\u0430\u043c \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e \u0445\u043e\u0434\u0438\u0442. \u0412 standalone-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 (\u0431\u0435\u0437 Tsak) \u0432\u044b \u0437\u0430\u0432\u043e\u0434\u0438\u0442\u0435 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0440\u0443\u043a\u0430\u043c\u0438. \u0412\u043e\u0442 \u0433\u043e\u043b\u044b\u0439\u00a0<code>RouteContext<\/code>\u00a0\u0438\u0437 \u0434\u0435\u043c\u043e\u00a0<code>Llm.HttpShell<\/code>\u00a0\u2014 \u043d\u0438 DI, \u043d\u0438 Tsak:<\/p>\n<pre><code>var ctx = new RouteContext(sp, contextId: \"llm-http-shell\");ctx.AddComponent(new HttpComponent { ServerManager = new SharedHttpServerManager() });\/\/ ...ctx.AddRoutes(r =&gt; r.From(\"http:0.0.0.0:5088\/api\/llm\/shell?inOut=true\") ... );<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041b\u0438\u0431\u043e \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0447\u0435\u0440\u0435\u0437 DI \u2014\u00a0<code>AddRedbRouteHttp()<\/code>\u00a0\u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0442\u043e\u0442 \u0436\u0435 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d-\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0437\u0430 \u0432\u0430\u0441. \u0412 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0435\u0440\u0432\u044b\u0439\u00a0<code>From(\"http:host:port\/...\")<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442, \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u0432\u0435\u0436\u0438\u0439 Kestrel \u0447\u0435\u0440\u0435\u0437\u00a0<code>CreateSlimBuilder()<\/code>\u00a0\u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043f\u0430\u0440\u044b\u00a0<code>(host, port)<\/code>, \u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b \u043d\u0430 \u0442\u043e\u043c \u0436\u0435\u00a0<code>(host, port)<\/code>\u00a0\u043a \u043d\u0435\u043c\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f.<\/p>\n<blockquote>\n<p><strong>\u0422\u043e\u043d\u043a\u043e\u0441\u0442\u044c:<\/strong>\u00a0\u043f\u0443\u043b\u0438\u043d\u0433 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u00a0<strong>\u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430<\/strong>\u00a0<code>SharedHttpServerManager<\/code>. \u0417\u0430\u0432\u0435\u0434\u0451\u0442\u0435 \u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u0438 \u043d\u0430\u0446\u0435\u043b\u0438\u0442\u0435 \u043e\u0431\u0430 \u043d\u0430 \u043e\u0434\u0438\u043d \u043f\u043e\u0440\u0442 \u2014 \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0441\u043e\u043a\u0435\u0442\u0430, \u0430 \u043d\u0435 \u0448\u0430\u0440\u0438\u043d\u0433. \u0413\u0430\u0440\u0430\u043d\u0442\u0438\u044e \u00ab\u043e\u0434\u0438\u043d Kestrel \u043d\u0430\u00a0<code>(host, port)<\/code>\u00bb \u0434\u0430\u0451\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0431\u0449\u0438\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440: \u0432 Tsak \u044d\u0442\u043e \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u0432 standalone \u2014 \u043d\u0430 \u0432\u0430\u0448\u0435\u0439 \u0441\u043e\u0432\u0435\u0441\u0442\u0438.<\/p>\n<\/blockquote>\n<p>\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0432\u044b\u0432\u043e\u0434: \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 (\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430) Kestrel \u0440\u043e\u0432\u043d\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043f\u0430\u0440\u00a0<code>(host, port)<\/code>. \u0421\u0435\u0441\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u043c \u043d\u0430 \u043f\u043e\u0440\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u0441\u043b\u0443\u0448\u0430\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0439 redb-\u043c\u0430\u0440\u0448\u0440\u0443\u0442 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0430\u0434\u043c\u0438\u043d\u043a\u0443 Tsak), \u2014 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u00ab\u043d\u0435 \u043f\u043b\u043e\u0434\u0438\u0442\u044c\u00bb. \u041a\u043e\u043d\u0444\u043b\u0438\u043a\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0441\u043e\u043a\u0435\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0440\u0442 \u0437\u0430\u043d\u044f\u043b\u00a0<strong>\u0447\u0443\u0436\u043e\u0439<\/strong>, \u043d\u0435-redb \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u0443 \u0448\u0438\u043d\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0432\u0440\u043e\u0434\u0435 MassTransit \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0442<\/h4>\n<p>\u041f\u043e\u043b\u0435\u0437\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0441\u00a0<a href=\"https:\/\/masstransit.io\/\" rel=\"noopener noreferrer nofollow\">MassTransit<\/a>\u00a0\u2014 \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 .NET-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438. \u0423 \u043d\u0435\u0433\u043e\u00a0<strong>\u043d\u0435\u0442<\/strong>\u00a0\u043d\u0438 HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u0430, \u043d\u0438 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043d\u0438 \u00abhttp \u043a\u0430\u043a \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430\u00bb. \u0418 \u044d\u0442\u043e \u043d\u0435 \u0443\u043f\u0443\u0449\u0435\u043d\u0438\u0435, \u0430 \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b.<\/p>\n<p>MassTransit \u2014 \u044d\u0442\u043e\u00a0<strong>\u0448\u0438\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439<\/strong>\u00a0(message bus) \u043f\u043e\u0432\u0435\u0440\u0445 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432: RabbitMQ, Azure Service Bus, Amazon SQS, \u043f\u043b\u044e\u0441 Kafka\/Event Hubs \u043a\u0430\u043a \u00abrider\u00bb. \u0415\u0433\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u2014 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u043e\u043a\u0435\u0440 \u0441 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u044f\u043c\u0438, \u0440\u0435\u0442\u0440\u0430\u044f\u043c\u0438 \u0438 \u0441\u0430\u0433\u0430\u043c\u0438; \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u044b \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b \u043a\u00a0<strong>\u0442\u0438\u043f\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/strong>\u00a0(<code>IConsumer&lt;TMessage&gt;<\/code>), \u0430 \u043d\u0435 \u043a URI-\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0443. HTTP \u0432 \u044d\u0442\u0443 \u043a\u0430\u0440\u0442\u0438\u043d\u0443 \u043d\u0435 \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f: \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0442 async\/durable-\u043c\u043e\u0434\u0435\u043b\u0438 \u0448\u0438\u043d\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0451\u043c HTTP MassTransit \u043e\u0442\u0434\u0430\u0451\u0442 \u043d\u0430 \u043e\u0442\u043a\u0443\u043f <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> \u2014 \u0432\u044b \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0438\u043b\u0438 minimal API \u0438 \u0443\u0436\u0435 \u043e\u0442\u0442\u0443\u0434\u0430 \u0434\u0435\u043b\u0430\u0435\u0442\u0435\u00a0<code>Publish<\/code>\/<code>Send<\/code>\u00a0\u0432 \u0448\u0438\u043d\u0443. \u0413\u0440\u0430\u043d\u0438\u0446\u0430 \u00abHTTP \u2192 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u00bb \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442\u00a0<strong>\u0441\u043d\u0430\u0440\u0443\u0436\u0438<\/strong>\u00a0\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0440\u0443\u043a\u0430\u043c\u0438, \u0432 \u043a\u043e\u0434\u0435 \u0432\u0430\u0448\u0435\u0433\u043e \u0445\u043e\u0441\u0442\u0430.<\/p>\n<p>redb.Route (\u043a\u0430\u043a \u0438\u00a0<a href=\"https:\/\/camel.apache.org\/\" rel=\"noopener noreferrer nofollow\">Apache Camel<\/a>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043d \u0440\u0430\u0432\u043d\u044f\u0435\u0442\u0441\u044f) \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0438\u043d\u0430\u0447\u0435: \u044d\u0442\u043e\u00a0<strong>\u0434\u0432\u0438\u0436\u043e\u043a \u043c\u0435\u0434\u0438\u0430\u0446\u0438\u0438<\/strong>, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e HTTP \u2014 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442, \u043a\u0430\u043a Kafka \u0438\u043b\u0438 Rabbit. HTTP-\u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u0442 \u0436\u0435\u00a0<code>Exchange<\/code>, \u0447\u0442\u043e \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438\u0437 \u0431\u0440\u043e\u043a\u0435\u0440\u0430, \u0438 \u0435\u0434\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u0442\u0435 \u0436\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b EIP. \u041f\u043e\u044d\u0442\u043e\u043c\u0443\u00a0<code>From(\"http:...\")<\/code>\u00a0\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0430\u043a \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430, \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0441\u0430\u043c \u0432\u043b\u0430\u0434\u0435\u0435\u0442 Kestrel&#8217;\u043e\u043c, \u0430 \u043c\u043e\u0441\u0442 \u00abHTTP \u2192 Kafka \u2192 SQL \u2192 \u043e\u0442\u0432\u0435\u0442\u00bb \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 DSL-\u0446\u0435\u043f\u043e\u0447\u043a\u043e\u0439, \u043d\u0435 \u0432\u044b\u0445\u043e\u0434\u044f \u0438\u0437 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p>\n<p>\u042d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u043e\u0434 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438, \u0430 \u043d\u0435 \u00ab\u043b\u0443\u0447\u0448\u0435\/\u0445\u0443\u0436\u0435\u00bb: MassTransit \u0441\u0438\u043b\u0451\u043d \u0432 \u043d\u0430\u0434\u0451\u0436\u043d\u043e\u0439 \u0431\u0440\u043e\u043a\u0435\u0440\u043d\u043e\u0439 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0435 \u0438 \u0441\u0430\u0433\u0430\u0445 \u043f\u043e\u0432\u0435\u0440\u0445 \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439; Camel-\u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0434\u0432\u0438\u0436\u043a\u0438 \u2014 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u0448\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u043e\u0440\u043e\u0434\u043d\u044b\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u044b \u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443. \u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440 \u2014 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u043e \u0447\u0443\u0436\u0435\u0440\u043e\u0434\u043d\u0430\u044f \u043f\u0435\u0440\u0432\u043e\u043c\u0443.<\/p>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 3\u00bd. \u00ab\u041d\u043e \u044f \u043b\u044e\u0431\u043b\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b\u00bb \u2014\u00a0redb.Route.Controllers<\/h3>\n<p>\u0422\u0443\u0442 \u043e\u0431\u044b\u0447\u043d\u043e \u0440\u0430\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u0443\u0449\u0451\u043d\u043d\u044b\u0439 \u0433\u043e\u043b\u043e\u0441:\u00a0<em>\u00ab\u0410\u0442\u0440\u0438\u0431\u0443\u0442\u044b,\u00a0<\/em><code><em>[HttpGet]<\/em><\/code><em>, model binding \u2014 \u043c\u043d\u0435 \u044d\u0442\u043e \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f, \u044f \u043d\u0435 \u0445\u043e\u0447\u0443 \u043f\u0438\u0441\u0430\u0442\u044c\u00a0<\/em><code><em>.Choice()<\/em><\/code><em>\u00a0\u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442!\u00bb<\/em>\u00a0\u0421\u043f\u0440\u0430\u0432\u0435\u0434\u043b\u0438\u0432\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 \u2014\u00a0<code>redb.Route.Controllers<\/code>. \u041e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u0443\u044e \u044d\u0440\u0433\u043e\u043d\u043e\u043c\u0438\u043a\u0443 MVC-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432, \u043d\u043e\u00a0<strong>\u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0445\u043e\u0441\u0442\u0438\u043d\u0433-\u043c\u043e\u0434\u0435\u043b\u044c <\/strong><a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\"><strong>ASP.NET<\/strong><\/a>. \u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c\u0441\u044f, \u0432 \u0447\u0451\u043c \u0444\u043e\u043a\u0443\u0441.<\/p>\n<h4>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a ASP.NET \u2014 \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u043e\u043d<\/h4>\n<p>\u0412\u043e\u0442 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 (\u0438\u0437 \u0442\u0435\u0441\u0442\u043e\u0432\u00a0<code>redb.Route.Tests.Controllers<\/code>):<\/p>\n<pre><code>[Route(\"modules\")]public class ModulesController : RedbController{    [HttpGet]    public string[] GetAll() =&gt; [\"module1\", \"module2\"];    [HttpGet(\"{id}\")]    public string GetById([FromRoute(\"id\")] string id) =&gt; $\"module-{id}\";    [HttpPost]    public object Create([FromBody] CreateModuleRequest request) =&gt;        new { created = request.Name };    [HttpPut(\"{id}\")]    public object Update([FromRoute(\"id\")] string id, [FromBody] CreateModuleRequest request) =&gt;        new { updated = id, name = request.Name };    [HttpDelete(\"{id}\")]    public void Delete([FromRoute(\"id\")] string id) { }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u043d\u0430\u043a\u043e\u043c\u043e \u0434\u043e \u0431\u043e\u043b\u0438:\u00a0<code>[Route]<\/code>\u00a0\u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0435,\u00a0<code>[HttpGet]\/[HttpPost]\/[HttpPut]\/[HttpDelete]\/[HttpPatch]<\/code>\u00a0\u043d\u0430 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 (\u0441 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0434-\u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c\u00a0<code>\"{id}\"<\/code>), \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0447\u0435\u0440\u0435\u0437\u00a0<code>[FromBody]<\/code>,\u00a0<code>[FromRoute]<\/code>,\u00a0<code>[FromQuery]<\/code>,\u00a0<code>[FromHeader]<\/code>,\u00a0<code>[FromProperty]<\/code>. \u0412\u0435\u0440\u043d\u0443\u043b \u043e\u0431\u044a\u0435\u043a\u0442 \u2014 \u043e\u043d \u0443\u0435\u0434\u0435\u0442 \u0432 JSON.<\/p>\n<p>\u041d\u043e \u0434\u0432\u0430 \u043e\u0442\u043b\u0438\u0447\u0438\u044f \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u044b:<\/p>\n<ol>\n<li>\n<p>\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u2014\u00a0<code><strong>RedbController<\/strong><\/code>, \u0430 \u043d\u0435\u00a0<code>ControllerBase<\/code>. \u0423 \u043d\u0435\u0433\u043e \u043d\u0435\u0442\u00a0<code>HttpContext<\/code>,\u00a0<code>IActionResult<\/code>,\u00a0<code>[ApiController]<\/code>. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u2014 \u0434\u0432\u0430 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430:\u00a0<code>Context<\/code>\u00a0(\u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442) \u0438\u00a0<code>Exchange<\/code>\u00a0(\u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435). \u0422\u043e \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0432\u0438\u0434\u0438\u0442\u00a0<code>Exchange<\/code>, \u0430 \u043d\u0435 HTTP.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u00a0<strong>\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e-\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u0435\u043d<\/strong>. \u041e\u043d \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e HTTP. \u042d\u0442\u043e \u0441\u0442\u0430\u043d\u0435\u0442 \u0432\u0430\u0436\u043d\u043e \u0447\u0435\u0440\u0435\u0437 \u0430\u0431\u0437\u0430\u0446.<\/p>\n<\/li>\n<\/ol>\n<h4>\u041a\u0430\u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442<\/h4>\n<p>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u2014 \u044d\u0442\u043e \u043d\u0435 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442, \u0430\u00a0<strong>\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430<\/strong>. \u0412\u0435\u0448\u0430\u0435\u0442\u0435 \u0435\u0433\u043e \u043d\u0430 HTTP-\u0432\u0445\u043e\u0434 \u0447\u0435\u0440\u0435\u0437\u00a0<code>.RedbHttpController&lt;T&gt;()<\/code>:<\/p>\n<pre><code>From(\"http:0.0.0.0:5088\/api\/{**path}?inOut=true\")    .RouteId(\"modules-api\")    .RedbHttpController&lt;ModulesController&gt;();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0435\u0441\u0442\u0440 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u043c\u0438 (\u0438\u043b\u0438 \u0441\u043a\u0430\u043d\u043e\u043c \u0441\u0431\u043e\u0440\u043a\u0438):<\/p>\n<pre><code>var registry = new ControllerRegistry();registry.RegisterController(typeof(ModulesController));registry.RegisterController(typeof(ContextsController));\/\/ \u043b\u0438\u0431\u043e: registry.RegisterAssembly(typeof(ModulesController).Assembly);From(\"http:0.0.0.0:5088\/api\/{**path}?inOut=true\")    .RedbHttpController(registry);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u00a0<code>{**path}<\/code>\u00a0\u2014 HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0438\u0437 \u0447\u0430\u0441\u0442\u0438 5 \u043b\u043e\u0432\u0438\u0442\u00a0<strong>\u0432\u0441\u0451<\/strong>\u00a0\u043f\u043e\u0434\u00a0<code>\/api<\/code>, \u043a\u043b\u0430\u0434\u0451\u0442 \u0432\u00a0<code>Exchange<\/code>\u00a0\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438\u00a0<code>redbHttp.Method<\/code>,\u00a0<code>redbHttp.Path<\/code>,\u00a0<code>redbHttp.RouteParam.*<\/code>,\u00a0<code>redbHttp.QueryParam.*<\/code>, \u0430 \u0443\u0436\u0435\u00a0<code>HttpControllerDispatcher<\/code>\u00a0\u0441\u0430\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u0438\u0445 \u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u043d\u0443\u0436\u043d\u044b\u0439 \u044d\u043a\u0448\u0435\u043d. \u041d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432:<\/p>\n<pre><code>\/\/ HttpControllerDispatcher.Process (\u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043e)var method = exchange.In.GetHeader&lt;string&gt;(\"redbHttp.Method\");var path   = exchange.In.GetHeader&lt;string&gt;(\"redbHttp.Path\");var action = _registry.Resolve(method, normalizedPath, out var routeParams);if (action is null) { WriteError(exchange, 404, \"NotFound\", ...); return; }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u2014 \u0441\u0432\u043e\u044f, \u043d\u0435 \u043e\u0442 ASP.NET<\/h4>\n<p><code>ControllerRegistry.Resolve<\/code>\u00a0\u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u00a0<code>(\u043c\u0435\u0442\u043e\u0434, \u043f\u0443\u0442\u044c)<\/code>\u00a0\u0441 \u044d\u043a\u0448\u0435\u043d\u043e\u043c \u043f\u043e \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430\u043c, \u0432\u044b\u0431\u0438\u0440\u0430\u044f\u00a0<strong>\u0441\u0430\u043c\u044b\u0439 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0439<\/strong>\u00a0(\u043b\u0438\u0442\u0435\u0440\u0430\u043b\u044b \u0431\u044c\u044e\u0442\u00a0<code>{param}<\/code>):\u00a0<code>GET \/me\/sessions\/current<\/code>\u00a0\u0432\u044b\u0438\u0433\u0440\u0430\u0435\u0442 \u0443\u00a0<code>GET \/me\/sessions\/{id}<\/code>. \u042d\u0442\u043e \u0442\u043e\u0442 \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u0438, \u0447\u0442\u043e \u0438 \u0443 \u043e\u0431\u0449\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u0447\u0430\u0441\u0442\u0438 4, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432.<\/p>\n<p>\u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 (<code>ResolveHttpParameter<\/code>) \u0440\u043e\u0432\u043d\u043e \u0442\u0430, \u0447\u0442\u043e \u043e\u0431\u0435\u0449\u0430\u044e\u0442 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b:\u00a0<code>[FromBody]<\/code>\u00a0\u2014 JSON-\u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u0437\u00a0<code>byte[]<\/code>,\u00a0<code>[FromRoute]<\/code>\u00a0\u2014 \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430,\u00a0<code>[FromQuery]<\/code>\u00a0\u2014 \u0438\u0437\u00a0<code>redbHttp.QueryParam.*<\/code>,\u00a0<code>[FromHeader]<\/code>\u00a0\/\u00a0<code>[FromProperty]<\/code>\u00a0\u2014 \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432\/\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u00a0<code>Exchange<\/code>. \u0411\u0435\u0437 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u2014 \u043f\u0440\u043e\u0431\u0443\u0435\u0442 route-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043f\u043e \u0438\u043c\u0435\u043d\u0438, \u0438\u043d\u0430\u0447\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0442\u0438\u043f \u0435\u0434\u0435\u0442 \u0438\u0437 \u0442\u0435\u043b\u0430.<\/p>\n<p>\u041e\u0442\u0432\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a: \u0432\u0435\u0440\u043d\u0443\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u2192 JSON (camelCase, \u0441\u00a0<code>UnsafeRelaxedJsonEscaping<\/code>, \u0447\u0442\u043e\u0431\u044b \u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430 \u0438 \u044d\u043c\u043e\u0434\u0437\u0438 \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0438\u0441\u044c \u0432\u00a0<code>\u0410<\/code>), \u0441\u0442\u0430\u0442\u0443\u0441\u00a0<code>200<\/code>; \u0432\u0435\u0440\u043d\u0443\u043b\u0438\u00a0<code>null<\/code>\/<code>void<\/code>\u00a0\u2192\u00a0<code>204<\/code>; \u043a\u0438\u043d\u0443\u043b\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u2192 \u043a\u043e\u043d\u0432\u0435\u0440\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u00a0<code>500<\/code>\u00a0(\u0434\u043b\u044f \u043d\u0435\u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u2014\u00a0<code>404<\/code>). \u0414\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u00a0<code>status.code<\/code>\u00a0\u0438\u00a0<code>redbHttp.ResponseCode<\/code>, \u0430 HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0438\u0437 \u0447\u0430\u0441\u0442\u0438 5 \u0438\u0445 \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442. \u041a\u0440\u0443\u0433 \u0437\u0430\u043c\u043a\u043d\u0443\u043b\u0441\u044f.<\/p>\n<h4>\u0417\u0430\u0447\u0435\u043c \u0442\u0430\u043a, \u0430 \u043d\u0435 \u00ab\u043a\u0430\u043a \u0432 ASP.NET\u00bb<\/h4>\n<p>\u0412\u043e\u0442 \u0440\u0430\u0434\u0438 \u0447\u0435\u0433\u043e \u0432\u0441\u0451 \u0437\u0430\u0442\u0435\u0432\u0430\u043b\u043e\u0441\u044c. \u0422\u043e\u0442 \u0436\u0435\u00a0<code>ModulesController<\/code>, \u043d\u0438 \u0441\u0442\u0440\u043e\u0447\u043a\u0438 \u043d\u0435 \u043c\u0435\u043d\u044f\u044f, \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c\u00a0<strong>\u043d\u0435 \u043f\u043e HTTP<\/strong>:<\/p>\n<pre><code>\/\/ \u0442\u043e\u0442 \u0436\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u2014 \u043f\u043e gRPCFrom(grpcConsumer).RedbGrpcController&lt;ModulesController&gt;();\/\/ \u0442\u043e\u0442 \u0436\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u2014 \u043f\u043e SignalRFrom(signalRConsumer).RedbSignalRController&lt;ModulesController&gt;();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>RedbController<\/code>\u00a0\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e-\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u0435\u043d \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u00a0<code>Exchange<\/code>, \u0430 \u043d\u0435 \u0441\u00a0<code>HttpContext<\/code>. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> \u0442\u0430\u043a \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u2014 \u043e\u043d \u043d\u0430\u043c\u0435\u0440\u0442\u0432\u043e \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a HTTP-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0443. \u0410 \u0440\u0430\u0437\u00a0<code>.RedbHttpController&lt;T&gt;()<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440, \u043e\u043d\u00a0<strong>\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f<\/strong>\u00a0\u0441 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c DSL: \u0434\u043e \u043d\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c\u00a0<code>.Throttle()<\/code>, \u043f\u043e\u0441\u043b\u0435 \u2014\u00a0<code>.WireTap()<\/code>, \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u00a0<code>OnException<\/code>\/<code>TryCatch<\/code>, \u0441\u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u00a0<code>.Choice()<\/code>\u00a0\u0438\u0437 \u0447\u0430\u0441\u0442\u0438 1.<\/p>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c: \u043b\u044e\u0431\u0438\u0442\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u2014 \u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b. \u041f\u0440\u043e\u0441\u0442\u043e \u0437\u043d\u0430\u0439\u0442\u0435, \u0447\u0442\u043e \u043f\u043e\u0434 \u043d\u0438\u043c\u0438 \u043d\u0435 <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> MVC, \u0430 \u0442\u043e\u0442 \u0436\u0435\u00a0<code>Exchange<\/code>\u00a0\u0438 \u0442\u043e\u0442 \u0436\u0435 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430. \u0412\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0435 \u044d\u0440\u0433\u043e\u043d\u043e\u043c\u0438\u043a\u0443, \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u044f \u0445\u043e\u0441\u0442\u0438\u043d\u0433-\u043c\u043e\u0434\u0435\u043b\u044c.<\/p>\n<h4>\u0418 \u044d\u0442\u043e \u043d\u0435 \u0442\u0435\u043e\u0440\u0438\u044f \u2014 \u043d\u0430 \u044d\u0442\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u0430\u043c Tsak<\/h4>\n<p>\u041b\u0443\u0447\u0448\u0435\u0435 \u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e, \u0447\u0442\u043e \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u043e\u0435\u0432\u043e\u0439:\u00a0<strong>\u0432\u0441\u044f REST-\u0430\u0434\u043c\u0438\u043d\u043a\u0430 \u0441\u0430\u043c\u043e\u0433\u043e Tsak \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0440\u043e\u0432\u043d\u043e \u0442\u0430\u043a<\/strong>.\u00a0<code>ContextsController<\/code>,\u00a0<code>RoutesController<\/code>,\u00a0<code>ModulesController<\/code>,\u00a0<code>AuthController<\/code>,\u00a0<code>UsersController<\/code>,\u00a0<code>SchedulerController<\/code>,\u00a0<code>LogsController<\/code>\u00a0\u0438 \u0435\u0449\u0451 \u0441 \u0434\u0435\u0441\u044f\u0442\u043e\u043a (<code>redb.Tsak.Core\/Controllers<\/code>) \u2014 \u0432\u0441\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u00a0<code>RedbController<\/code>\u00a0\u0438 \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u044b \u0442\u0435\u043c\u0438 \u0436\u0435\u00a0<code>[Route]<\/code>\u00a0\/\u00a0<code>[HttpGet]<\/code>\u00a0\/\u00a0<code>[HttpPost]<\/code>\u00a0\/\u00a0<code>[FromRoute]<\/code>\u00a0\/\u00a0<code>[FromQuery]<\/code>. \u0412\u043e\u0442 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e\u00a0<code>ContextsController<\/code>:<\/p>\n<pre><code>[Route(\"\/api\/contexts\")]public class ContextsController : RedbController{    [HttpGet(\"\")]    public object? ListContexts() =&gt; \/* ... *\/;    [HttpGet(\"\/{name}\")]    public object? GetContext([FromRoute(\"name\")] string name) =&gt; \/* ... *\/;    [HttpPost(\"\/{name}\/stop\")]    public async Task&lt;object?&gt; StopContext(        [FromRoute(\"name\")] string name,        [FromQuery(\"timeoutSeconds\")] int? timeoutSeconds = null) =&gt; \/* ... *\/;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Tsak \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0438\u0445 \u0441\u0431\u043e\u0440\u043a\u0443 (<code>ControllerRegistry.RegisterAssembly<\/code>) \u0438 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0438\u0437\u0443\u0435\u0442 \u0447\u0435\u0440\u0435\u0437\u00a0<code>ControllerDispatcherProcessor<\/code>\u00a0\u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435\u00a0<code>_system<\/code>\u00a0\u2014 \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 HTTP-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0435, \u0447\u0442\u043e \u0438 \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u043e\u0431\u043a\u0430\u0442\u0430\u043d\u044b \u043d\u0430 \u043f\u0440\u043e\u0434\u0435 \u043d\u0438\u0447\u0443\u0442\u044c \u043d\u0435 \u043c\u0435\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u0441\u0430\u043c HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440: \u0434\u0430\u0448\u0431\u043e\u0440\u0434 \u0438 CLI Tsak \u0445\u043e\u0434\u044f\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u043d\u0438\u0445.<\/p>\n<blockquote>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440\u00a0<code>redb.Route.Controllers<\/code>\u00a0(\u0440\u0435\u0435\u0441\u0442\u0440, \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u044d\u043a\u0448\u0435\u043d\u043e\u0432\u00a0<code>IControllerActionFilter<\/code>, gRPC\/SignalR-\u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u044b, \u043a\u043e\u043d\u0432\u0435\u0440\u0442 \u043e\u0448\u0438\u0431\u043e\u043a) \u2014 \u0442\u0435\u043c\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0441\u0435\u0440\u0438\u0438. \u0417\u0434\u0435\u0441\u044c \u2014 \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043a\u0440\u044b\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u0430 \u0433\u0434\u0435 \u043c\u043e\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b\u00bb.<\/p>\n<\/blockquote>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 4. \u041e\u0434\u0438\u043d Kestrel \u043d\u0430 (host, port) \u2014\u00a0SharedHttpServerManager<\/h3>\n<p>\u0421\u0430\u043c\u0430\u044f \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u0430 \u2014 \u0442\u043e, \u0447\u0442\u043e\u00a0<strong>\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u043f\u043e\u0440\u0442<\/strong>. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0442\u0440\u0438\u00a0<code>From(...)<\/code>\u00a0\u043d\u0430\u00a0<code>0.0.0.0:5088<\/code>\u00a0\u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438 (<code>\/api\/demo<\/code>,\u00a0<code>\/api\/echo<\/code>,\u00a0<code>\/api\/llm\/ask<\/code>), \u043f\u043e\u0434\u043d\u0438\u043c\u0435\u0442\u0441\u044f\u00a0<strong>\u043e\u0434\u0438\u043d<\/strong>\u00a0Kestrel, \u0430 \u043d\u0435 \u0442\u0440\u0438.<\/p>\n<p>\u042d\u0442\u0438\u043c \u0437\u0430\u0432\u0435\u0434\u0443\u0435\u0442\u00a0<code>SharedHttpServerManager<\/code>. \u041a\u043b\u044e\u0447 \u2014 \u043f\u0430\u0440\u0430\u00a0<code>(host, port)<\/code>:<\/p>\n<pre><code>private readonly ConcurrentDictionary&lt;string, ServerEntry&gt; _servers = new(...);private static string BuildKey(string host, int port) =&gt; $\"{host}:{port}\";<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430<\/h4>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442, \u043e\u043d \u043d\u0435 \u00ab\u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u00bb, \u0430\u00a0<strong>\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043c\u0430\u0440\u0448\u0440\u0443\u0442<\/strong>\u00a0\u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0434\u043b\u044f \u0441\u0432\u043e\u0435\u0433\u043e\u00a0<code>(host, port)<\/code>. \u0421\u0435\u0440\u0432\u0435\u0440 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043b\u0435\u043d\u0438\u0432\u043e \u2014 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438:<\/p>\n<pre><code>\/\/ HttpConsumer.Start (\u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043e)_registration = _serverManager.RegisterRoute(    host, port, path, _options.Methods, HandleRequest,    ssl, _options.SslCertPath, _options.SslCertPassword,    corsOptions, _options.MaxRequestBodySize, _options.Protocol);await _serverManager.EnsureStarted(host, port, ct);BaseUrl = _serverManager.GetBaseUrl(host, port);   \/\/ \u043d\u0430\u043f\u0440. \"http:\/\/localhost:5088\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>RegisterRoute<\/code>\u00a0\u043a\u043b\u0430\u0434\u0451\u0442\u00a0<code>RouteRegistration<\/code>\u00a0(\u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0443\u0442\u0438 + \u043c\u0435\u0442\u043e\u0434\u044b + \u0445\u0435\u043d\u0434\u043b\u0435\u0440 + CORS) \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u0437\u0430\u043f\u0438\u0441\u0438\u00a0<code>ServerEntry<\/code>.\u00a0<code>EnsureStarted<\/code>\u00a0\u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 Kestrel, \u0435\u0441\u043b\u0438 \u043e\u043d \u0435\u0449\u0451 \u043d\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d; \u0435\u0441\u043b\u0438 \u0443\u0436\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u2014 no-op.<\/p>\n<h4>\u0414\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044f: \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432<\/h4>\n<p>\u0412\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u0440\u0438\u043b\u0435\u0442\u0430\u044e\u0442 \u0432 \u043e\u0434\u0438\u043d\u00a0<code>HandleCatchAll<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u0438\u0449\u0435\u0442 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442:<\/p>\n<pre><code>private static async Task HandleCatchAll(ServerEntry entry, HttpContext ctx){    var match = entry.MatchRoute(ctx.Request.Path, ctx.Request.Method);    if (match.Registration is null)    {        \/\/ \u043f\u0443\u0442\u044c \u0441\u043e\u0432\u043f\u0430\u043b, \u043d\u043e \u043c\u0435\u0442\u043e\u0434 \u043d\u0435\u0442 \u2192 405; \u0438\u043d\u0430\u0447\u0435 \u2192 404        ctx.Response.StatusCode = match.PathMatched            ? StatusCodes.Status405MethodNotAllowed            : StatusCodes.Status404NotFound;        return;    }    if (match.RouteValues is not null)        ctx.Items[\"__redbRouteValues\"] = match.RouteValues;   \/\/ {id} \u0438 \u0442.\u043f. \u2014 \u0434\u0430\u043b\u044c\u0448\u0435 \u0432 Exchange    await match.Registration.Handler(ctx);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0443\u0442 \u0434\u0432\u0435 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0430\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c:<\/p>\n<p><strong>1. \u0420\u0430\u0437\u043b\u0438\u0447\u0438\u0435 404 \u0438 405.<\/strong>\u00a0\u0415\u0441\u043b\u0438 \u043f\u0443\u0442\u044c \u043d\u0430\u0448\u0451\u043b\u0441\u044f, \u0430 \u043c\u0435\u0442\u043e\u0434 \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d \u2014 \u0447\u0435\u0441\u0442\u043d\u044b\u0439\u00a0<code>405 Method Not Allowed<\/code>, \u0430 \u043d\u0435\u00a0<code>404<\/code>. \u041c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f, \u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c.<\/p>\n<p><strong>2. \u0428\u0430\u0431\u043b\u043e\u043d\u044b \u043f\u0443\u0442\u0435\u0439 \u0438 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u0438.<\/strong>\u00a0\u041f\u0443\u0442\u0438 \u043f\u0430\u0440\u0441\u044f\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437\u00a0<code>TemplateParser<\/code>\/<code>TemplateMatcher<\/code>\u00a0\u0438\u0437 <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a>-\u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u2014 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b\u00a0<code>{id}<\/code>\u00a0\u0438 catch-all\u00a0<code>{**rest}<\/code>. \u041d\u043e \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u2014\u00a0<strong>\u043d\u0435<\/strong>\u00a0\u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0430 \u043f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u0438 (<code>ServerEntry.GetCompiled<\/code>):<\/p>\n<pre><code>_compiled = built    .OrderBy(x =&gt; x.spec.HasCatchAll ? 1 : 0)   \/\/ \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u2014 \u043f\u0435\u0440\u0432\u044b\u043c\u0438, catch-all \u2014 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c    .ThenByDescending(x =&gt; x.spec.Literals)      \/\/ \u0431\u043e\u043b\u044c\u0448\u0435 \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 = \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u0435\u0435    .ThenBy(x =&gt; x.spec.Parameters)              \/\/ \u043c\u0435\u043d\u044c\u0448\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 = \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u0435\u0435    .ThenBy(x =&gt; x.order)                        \/\/ \u043f\u0440\u0438 \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u0435 \u2014 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438    .Select(...).ToArray();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u0447\u0435\u043c? \u0427\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439\u00a0<code>\/api\/echo<\/code>\u00a0\u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u043b \u0443 catch-all\u00a0<code>\/{**path}<\/code>, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 \u043f\u043e\u0440\u0442\u0443, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 catch-all \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0440\u0430\u043d\u044c\u0448\u0435. \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430 catch-all \u00ab\u0441\u044a\u0435\u043b\u00bb \u0431\u044b \u0432\u0441\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b. \u041f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u0436\u0434\u0451\u0448\u044c \u043e\u0442 <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a>-\u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430.<\/p>\n<h4>\u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b: \u043f\u043e\u0434\u0441\u0447\u0451\u0442 \u0441\u0441\u044b\u043b\u043e\u043a<\/h4>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u0436\u0438\u0432\u0451\u0442 \u0440\u043e\u0432\u043d\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043d\u0451\u043c \u0435\u0441\u0442\u044c \u0445\u043e\u0442\u044c \u043e\u0434\u0438\u043d \u043c\u0430\u0440\u0448\u0440\u0443\u0442. \u041f\u0440\u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u0430:<\/p>\n<pre><code>\/\/ HttpConsumer.Stop_serverManager.UnregisterRoute(_registration);await _serverManager.StopIfEmpty(host, port, ct);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>StopIfEmpty<\/code>\u00a0\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0438 \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0435\u0442 Kestrel\u00a0<strong>\u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u043d\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c<\/strong>:<\/p>\n<pre><code>public async Task StopIfEmpty(string host, int port, ...){    if (entry.Routes.Count &gt; 0) return;   \/\/ \u0435\u0449\u0451 \u043a\u0442\u043e-\u0442\u043e \u0441\u043b\u0443\u0448\u0430\u0435\u0442 \u2014 \u043d\u0435 \u0442\u0440\u043e\u0433\u0430\u0435\u043c    _servers.TryRemove(key, out _);    await StopServer(entry, ct);          \/\/ graceful stop \u0441 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u043e\u043c 5 \u0441\u0435\u043a}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u043e\u0434\u0438\u043d \u0438\u0437 \u0442\u0440\u0451\u0445 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 5088 \u2014 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u0434\u0432\u0443\u0445. \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u2014 Kestrel \u0433\u0430\u0441\u0438\u0442\u0441\u044f. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430 \u043b\u0435\u0442\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0438 \u0443\u0431\u0438\u0440\u0430\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 \u0434\u0430\u0448\u0431\u043e\u0440\u0434:\u00a0<code>tsak route start demo-http-echo<\/code>\u00a0\/\u00a0<code>stop<\/code>), \u043d\u0435 \u0434\u0451\u0440\u0433\u0430\u044f \u0432\u0435\u0441\u044c \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<h4>\u0417\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u0441\u0445\u0435\u043c<\/h4>\n<p>\u041d\u0435\u043b\u044c\u0437\u044f \u043d\u0430 \u043e\u0434\u043d\u043e\u043c\u00a0<code>(host, port)<\/code>\u00a0\u043f\u043e\u0432\u0435\u0441\u0438\u0442\u044c \u0438 HTTP, \u0438 HTTPS \u2014 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0431\u0440\u043e\u0441\u0438\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438:<\/p>\n<pre><code>if (entry.Ssl != ssl)    throw new InvalidOperationException(        $\"Server on {host}:{port} is already registered as {(entry.Ssl ? \"HTTPS\" : \"HTTP\")}...\");<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 5. \u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440: \u043a\u0430\u043a HTTP-\u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f\u00a0Exchange<\/h3>\n<p>\u042d\u0442\u043e \u0441\u0435\u0440\u0434\u0446\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u2014 \u043c\u0435\u0442\u043e\u0434\u00a0<code>HttpConsumer.BuildExchange<\/code>. \u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0438\u043b\u0435\u0442\u0430\u0435\u0442 \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442.<\/p>\n<h4>\u0422\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/h4>\n<pre><code>if (request.ContentLength &gt; 0 || request.ContentType is not null){    if (_options.StreamRequest)        body = request.Body;                       \/\/ \u043f\u043e\u0442\u043e\u043a \u043a\u0430\u043a \u0435\u0441\u0442\u044c (passthrough)    else    {        using var ms = new MemoryStream();        await request.Body.CopyToAsync(ms, ...);        body = ms.ToArray();                        \/\/ \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0443\u0435\u043c \u0432 byte[]    }}var message = new Message(body);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0442\u0435\u043b\u043e\u00a0<strong>\u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u00a0<\/strong><code><strong>byte[]<\/strong><\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u0445 \u0432\u044b \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u0438\u0434\u0438\u0442\u0435\u00a0<code>.ConvertBody&lt;string&gt;()<\/code>\u00a0\u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435\u00a0<code>From<\/code>\u00a0\u2014 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0431\u0430\u0439\u0442\u044b \u0432 \u0441\u0442\u0440\u043e\u043a\u0443. \u041f\u0440\u0438\u00a0<code>streamRequest=true<\/code>\u00a0\u0442\u0435\u043b\u043e \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f\u00a0<code>Stream<\/code>\u00a0(\u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a), \u0438 \u0432\u0430\u0436\u043d\u0430\u044f \u0434\u0435\u0442\u0430\u043b\u044c \u0438\u0437 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u0432 \u043a\u043e\u0434\u0435: \u044d\u0442\u043e\u0442 \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 Kestrel,\u00a0<code>Exchange.DisposeAsync<\/code>\u00a0\u0435\u0433\u043e\u00a0<strong>\u043d\u0435<\/strong>\u00a0\u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442, \u043d\u043e \u043e\u043d \u0432\u0430\u043b\u0438\u0434\u0435\u043d \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<h4>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438: \u0447\u0442\u043e \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0434\u0451\u0442 \u0432\u00a0Exchange<\/h4>\n<p>\u042d\u0442\u043e, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0432\u0441\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438. \u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438\u00a0<code>Exchange<\/code>\u00a0\u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c\u00a0<code>redbHttp.<\/code>\u00a0(<code>HttpHeaders.cs<\/code>):<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a Exchange<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0427\u0442\u043e \u0432 \u043d\u0451\u043c<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041f\u0440\u0438\u043c\u0435\u0440<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.Method<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">HTTP-\u043c\u0435\u0442\u043e\u0434<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>POST<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.Path<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u0443\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>\/api\/demo<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.Url<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u043e\u043b\u043d\u044b\u0439 URL<\/p>\n<\/td>\n<td>\n<p align=\"left\"><a href=\"http:\/\/localhost:5088\/api\/demo?x=1\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:5088\/api\/demo?x=1<\/code><\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.Port<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u043e\u0440\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (int)<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>5088<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.Query<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0441\u044b\u0440\u0430\u044f query-\u0441\u0442\u0440\u043e\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>x=1&amp;y=2<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.QueryParam.&lt;\u0438\u043c\u044f&gt;<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 query-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>redbHttp.QueryParam.x<\/code>\u00a0=\u00a0<code>1<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.RouteParam.&lt;\u0438\u043c\u044f&gt;<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043f\u0443\u0442\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>\/users\/{id}<\/code>\u00a0\u2192\u00a0<a href=\"http:\/\/redbHttp.RouteParam.id\" rel=\"noopener noreferrer nofollow\"><code>redbHttp.RouteParam.id<\/code><\/a><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbHttp.RemoteAddress<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">IP \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>127.0.0.1<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>&lt;\u043b\u044e\u0431\u043e\u0439 HTTP-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a&gt;<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043a\u0430\u043a \u0435\u0441\u0442\u044c<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>Content-Type<\/code>,\u00a0<code>Authorization<\/code>,\u00a0<code>X-Chat-Id<\/code>\u2026<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0436\u043d\u044b\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<p><strong>\u041c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f query\/\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432.<\/strong>\u00a0\u0415\u0441\u043b\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f (<code>?tag=a&amp;tag=b<\/code>), \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u043a\u043b\u0435\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e:<\/p>\n<pre><code>message.Headers[$\"redbHttp.QueryParam.{qp.Key}\"] = qp.Value.Count switch{    0 =&gt; string.Empty,    1 =&gt; (object)qp.Value[0]!,    _ =&gt; string.Join(\",\", qp.Value!)};<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>Route-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430.<\/strong>\u00a0\u041f\u043e\u043c\u043d\u0438\u0442\u0435\u00a0<code>ctx.Items[\"__redbRouteValues\"]<\/code>\u00a0\u0438\u0437 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430? \u0412\u043e\u0442 \u0433\u0434\u0435 \u043e\u043d\u0438 \u0434\u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f:<\/p>\n<pre><code>if (httpContext.Items.TryGetValue(\"__redbRouteValues\", out var rvObj)    &amp;&amp; rvObj is RouteValueDictionary routeValues){    foreach (var (key, value) in routeValues)        if (value is not null)            message.Headers[$\"redbHttp.RouteParam.{key}\"] = value;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c\u00a0<code>From(\"http:0.0.0.0:8080\/users\/{id}\")<\/code>\u00a0\u0434\u0430\u0441\u0442 \u0432\u0430\u043c\u00a0<code>${<\/code><a href=\"http:\/\/header.redbHttp.RouteParam.id\" rel=\"noopener noreferrer nofollow\"><code>header.redbHttp.RouteParam.id<\/code><\/a><code>}<\/code>\u00a0\u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0435.<\/p>\n<p><strong>\u041f\u0441\u0435\u0432\u0434\u043e-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 HTTP\/2 \u043e\u0442\u0441\u0435\u0438\u0432\u0430\u044e\u0442\u0441\u044f.<\/strong>\u00a0\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0432\u0438\u0434\u0430\u00a0<code>:method<\/code>,\u00a0<code>:path<\/code>\u00a0(HTTP\/2) \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u2014\u00a0<code>if (header.Key.StartsWith(':')) continue;<\/code>.<\/p>\n<p><strong>\u0417\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u0438\u043c\u0451\u043d \u0437\u0430\u043f\u0440\u043e\u0441\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432.<\/strong>\u00a0\u0422\u043e\u043d\u043a\u0438\u0439, \u043d\u043e \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u0438\u043c\u0435\u043d\u0430 \u0432\u0441\u0435\u0445 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0432 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0438 \u043a\u043b\u0430\u0434\u0451\u0442 \u0435\u0433\u043e \u0432 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 Exchange:<\/p>\n<pre><code>exchange.Properties[\"redbHttp.RequestHeaderNames\"] = requestHeaderNames;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u0447\u0435\u043c \u2014 \u0441\u0442\u0430\u043d\u0435\u0442 \u044f\u0441\u043d\u043e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043e\u0442\u0432\u0435\u0442\u0430: \u0447\u0442\u043e\u0431\u044b\u00a0<strong>\u043d\u0435 \u043e\u0442\u0440\u0430\u0437\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u043e\u0442\u0432\u0435\u0442<\/strong>. \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e, \u0441\u043a\u0430\u0436\u0435\u043c, \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0439\u00a0<code>Host<\/code>\u00a0\u0438\u043b\u0438\u00a0<code>User-Agent<\/code>\u00a0\u043c\u043e\u0433 \u0431\u044b \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u0443\u0435\u0445\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.<\/p>\n<h4>\u041f\u0430\u0442\u0442\u0435\u0440\u043d \u043e\u0431\u043c\u0435\u043d\u0430: InOnly vs InOut<\/h4>\n<pre><code>exchange.Pattern = _options.InOut ? ExchangePattern.InOut : ExchangePattern.InOnly;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p><strong>InOnly<\/strong>\u00a0(\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e) \u2014 fire-and-forget. \u0421\u0435\u0440\u0432\u0435\u0440 \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043f\u0443\u0441\u0442\u044b\u043c\u00a0<code>200 OK<\/code>, \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043e\u0442\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u00ab\u0432 \u0444\u043e\u043d\u0435\u00bb \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u0432\u0435\u0442\u0430. \u042d\u0442\u043e \u0432\u0435\u0431\u0445\u0443\u043a-\u043f\u0440\u0438\u0451\u043c\u043d\u0438\u043a: \u00ab\u043f\u0440\u0438\u043d\u044f\u043b, \u0441\u043f\u0430\u0441\u0438\u0431\u043e\u00bb.<\/p>\n<\/li>\n<li>\n<p><strong>InOut<\/strong>\u00a0(<code>?inOut=true<\/code>) \u2014 request\/reply. \u0421\u0435\u0440\u0432\u0435\u0440\u00a0<strong>\u0436\u0434\u0451\u0442<\/strong>\u00a0\u043a\u043e\u043d\u0435\u0446 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0438 \u043e\u0442\u0434\u0430\u0451\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u0430\u043a HTTP-\u043e\u0442\u0432\u0435\u0442. \u042d\u0442\u043e API-\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438: \u0445\u043e\u0442\u0438\u0442\u0435 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0442\u0435\u043b\u043e \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u2014 \u043d\u0443\u0436\u0435\u043d\u00a0<code>inOut=true<\/code>. \u0418\u043d\u0430\u0447\u0435 \u0442\u0435\u043b\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b \u0441\u043e\u0431\u0440\u0430\u043b\u0438 \u0447\u0435\u0440\u0435\u0437\u00a0<code>.SetBody(...)<\/code>, \u043d\u0438\u043a\u0443\u0434\u0430 \u043d\u0435 \u0443\u0435\u0434\u0435\u0442 (\u0441\u043c.\u00a0<code>WriteResponse<\/code>\u00a0\u2014 \u0432\u0441\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0442\u0435\u043b\u0430 \u043f\u043e\u0434\u00a0<code>if (_options.InOut)<\/code>).<\/p>\n<h4>\u041e\u0442\u0432\u0435\u0442: \u043a\u0430\u043a\u00a0Exchange\u00a0\u0441\u043d\u043e\u0432\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f HTTP<\/h4>\n<p><code>WriteResponse<\/code>\u00a0\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 HTTP-\u043e\u0442\u0432\u0435\u0442. \u041f\u043e\u0440\u044f\u0434\u043e\u043a \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f\u00a0<strong>\u0441\u0442\u0430\u0442\u0443\u0441-\u043a\u043e\u0434\u0430<\/strong>\u00a0(\u043f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u0430):<\/p>\n<pre><code>var statusCode = _options.ResponseCode;                       \/\/ 3. \u0434\u0435\u0444\u043e\u043b\u0442 \u0438\u0437 \u043e\u043f\u0446\u0438\u0439 (200)if (responseMsg.Headers.TryGetValue(\"redbHttp.ResponseCode\", out var rc)) ...   \/\/ 1. \u044f\u0432\u043d\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043aelse if (responseMsg.Headers.TryGetValue(\"status.code\", out var sc)) ...        \/\/ 2. \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e-\u043d\u0435\u0439\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0439 fallback<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u0438\u0437 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c, \u0441\u043a\u0430\u0436\u0435\u043c,\u00a0<code>404<\/code>, \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a:<\/p>\n<pre><code>.SetHeader(\"redbHttp.ResponseCode\", 404)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>Content-Type<\/strong>\u00a0\u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0445\u043e\u0436\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u043e\u0439:\u00a0<code>redbHttp.ResponseContentType<\/code>\u00a0\u2192\u00a0<code>Message.ContentType<\/code>\u00a0\u2192 \u0434\u0435\u0444\u043e\u043b\u0442 \u0438\u0437 \u043e\u043f\u0446\u0438\u0439 (<code>application\/json<\/code>).<\/p>\n<p><strong>\u041f\u0435\u0440\u0435\u043d\u043e\u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0432 \u043e\u0442\u0432\u0435\u0442.<\/strong>\u00a0\u0412\u043e\u0442 \u0437\u0434\u0435\u0441\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e \u0441\u0430\u043c\u043e\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u00a0<code>RequestHeaderNames<\/code>. \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0438\u0437 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u043f\u0430\u0434\u0451\u0442 \u0432 HTTP-\u043e\u0442\u0432\u0435\u0442, \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043e\u043d \u043f\u0440\u043e\u0448\u0451\u043b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432:<\/p>\n<pre><code>foreach (var (key, value) in responseMsg.Headers){    if (value is null) continue;    if (requestHeaderNames?.Contains(key) == true) continue;  \/\/ \u043d\u0435 \u043e\u0442\u0440\u0430\u0436\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043d\u044b\u0435    if (HttpHeaders.NonBridgedHeaders.Contains(key)) continue; \/\/ hop-by-hop \u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435    if (HttpHeaders.IsRedbHeader(key)) continue;               \/\/ redbHttp.* \u2014 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435    if (IsInternalHeader(key)) continue;                       \/\/ redb*\/Camel* \u2014 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435    \/\/ ... \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u044c \u0434\u043b\u044f\u00a0<code>Set-Cookie<\/code>\u00a0\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043c\u0443\u043b\u044c\u0442\u0438-\u0437\u043d\u0430\u0447\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f\u00a0<code>StringValues<\/code>, \u0447\u0442\u043e\u0431\u044b <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> \u043e\u0442\u0434\u0430\u043b\u00a0<strong>\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430<\/strong>, \u0430 \u043d\u0435 \u043e\u0434\u0438\u043d \u0441\u043a\u043b\u0435\u0435\u043d\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432:<\/p>\n<pre><code>StringValues sv = value switch{    string s =&gt; s,    string[] arr =&gt; arr,    IEnumerable seq when value is not string =&gt;        seq.Cast&lt;object?&gt;().Select(o =&gt; o?.ToString() ?? \"\").ToArray(),    _ =&gt; value.ToString()};if (ContainsInvalidHeaderValueCharacters(sv)) continue;  \/\/ Kestrel \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 control-\/\u043d\u0435-ASCIIhttpContext.Response.Headers.TryAdd(key, sv);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<blockquote>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u0438 \u0438\u0437 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<\/strong>\u00a0\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0432 \u043e\u0442\u0432\u0435\u0442 \u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f\u00a0<strong>\u0432\u0441\u0435\u0433\u0434\u0430<\/strong>, \u0434\u0430\u0436\u0435 \u043a\u043e\u0433\u0434\u0430 \u0442\u0435\u043b\u043e \u043f\u0443\u0441\u0442\u043e\u0435. \u0418\u043d\u0430\u0447\u0435 \u0431\u0435\u0437\u0442\u0435\u043b\u0435\u0441\u043d\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b (302-\u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442, 204 No Content, \u043e\u0442\u0432\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u00a0<code>Set-Cookie<\/code>) \u043c\u043e\u043b\u0447\u0430 \u0442\u0435\u0440\u044f\u043b\u0438 \u0431\u044b\u00a0<code>Location<\/code>\/<code>Set-Cookie<\/code>. \u042d\u0442\u043e \u043f\u0440\u044f\u043c\u043e \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u0432 \u043a\u043e\u0434\u0435.<\/p>\n<\/blockquote>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 6. CORS \u043d\u0430 \u043e\u0431\u0449\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u2014 \u0431\u0435\u0437\u00a0app.UseCors()<\/h3>\n<p><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/HTTP\/CORS\" rel=\"noopener noreferrer nofollow\">CORS<\/a>\u00a0\u0432 <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> \u2014 \u044d\u0442\u043e middleware \u0438 \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438. \u0417\u0434\u0435\u0441\u044c middleware <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a>-CORS \u043d\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435. \u0412\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u2014\u00a0<strong>\u043e\u0434\u043d\u0430<\/strong>\u00a0\u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440-\u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443\u00a0<strong>\u043f\u043e \u0441\u043e\u0432\u043f\u0430\u0432\u0448\u0435\u043c\u0443 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0443<\/strong>. \u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a: \u043d\u0430 \u043e\u0434\u043d\u043e\u043c\u00a0<code>(host, port)<\/code>\u00a0\u0436\u0438\u0432\u0443\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b, \u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u0432\u043e\u044f CORS-\u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430. \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439\u00a0<code>UseCors<\/code>\u00a0\u0441 \u043e\u0434\u043d\u043e\u0439 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u043e\u0439 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u044d\u0442\u043e \u043d\u0435 \u0434\u0430\u0451\u0442.<\/p>\n<h4>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b CORS<\/h4>\n<p>\u041d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 (<code>HttpEndpointOptions<\/code>):<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 URI<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0421\u043c\u044b\u0441\u043b<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>cors=true<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>Cors<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c CORS \u0434\u043b\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>corsOrigins=...<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>CorsOrigins<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0431\u0435\u043b\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a origin&#8217;\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e, \u0438\u043b\u0438\u00a0<code>*<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>corsCredentials=true<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>CorsCredentials<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c\u00a0<code>Access-Control-Allow-Credentials<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u2014 (\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043a\u043e\u0434\u0430)<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>CorsOriginsResolver<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0434\u0435\u043b\u0435\u0433\u0430\u0442\u00a0<code>HttpRequest \u2192 string?<\/code>\u00a0\u0434\u043b\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430 origin<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 fluent-DSL:<\/p>\n<pre><code>.From(Http.Listen(\"\/api\").Port(8080).Cors(\"https:\/\/app.example.com\").CorsCredentials())<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043b\u044e\u0441\u00a0<strong>\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0435<\/strong>\u00a0\u0434\u0435\u0444\u043e\u043b\u0442\u044b \u043d\u0430 \u0432\u0435\u0441\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u2014 \u0447\u0435\u0440\u0435\u0437 DI:<\/p>\n<pre><code>services.AddRedbRouteHttp(cors =&gt;{    cors.Enabled = true;    cors.Origins = \"https:\/\/example.com\";});<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u044e\u0442 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0435 (<code>HttpComponent.ApplyCorsDefaults<\/code>).<\/p>\n<h4>\u041d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u043d\u0435\u044f\u0432\u043d\u043e\u0433\u043e\u00a0*<\/h4>\n<p>\u0421\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435: \u0435\u0441\u043b\u0438\u00a0<code>cors=true<\/code>, \u0432\u044b\u00a0<strong>\u043e\u0431\u044f\u0437\u0430\u043d\u044b<\/strong>\u00a0\u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043b\u0438\u0431\u043e\u00a0<code>corsOrigins<\/code>\u00a0(\u0432 \u0442.\u0447. \u044f\u0432\u043d\u043e\u0435\u00a0<code>\"*\"<\/code>\u00a0\u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432), \u043b\u0438\u0431\u043e \u0440\u0435\u0437\u043e\u043b\u0432\u0435\u0440. \u0418\u043d\u0430\u0447\u0435 \u2014 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435 (<code>HttpEndpointOptions.Validate<\/code>):<\/p>\n<pre><code>if (Cors &amp;&amp; string.IsNullOrEmpty(CorsOrigins) &amp;&amp; CorsOriginsResolver is null)    throw new ArgumentException(        \"Cors=true requires CorsOrigins (use \\\"*\\\" for public endpoints) or CorsOriginsResolver to be set.\");<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443: \u0441\u0442\u0430\u0440\u044b\u0439 \u043d\u0435\u044f\u0432\u043d\u044b\u0439\u00a0<code>*<\/code>\u00a0\u2014 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0444\u0443\u0442\u0433\u0430\u043d. \u0412 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0438 \u0441\u00a0<code>credentials<\/code>\u00a0\u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0435\u0433\u043e \u043c\u043e\u043b\u0447\u0430 \u043e\u0442\u0432\u0435\u0440\u0433\u0430\u0435\u0442, \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0447\u0430\u0441\u0430\u043c\u0438 \u0438\u0449\u0435\u0442, \u043f\u043e\u0447\u0435\u043c\u0443 \u00abCORS \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u00bb. \u041b\u0443\u0447\u0448\u0435 \u0443\u043f\u0430\u0441\u0442\u044c \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435 \u0441 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c.<\/p>\n<h4>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 (CorsDispatchMiddleware)<\/h4>\n<p>\u041f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u044c \u043e\u0434\u0438\u043d \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043e\u0431\u044a\u044f\u0432\u0438\u043b CORS (<code>entry.CorsEnabled<\/code>). \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430:<\/p>\n<pre><code>var route = entry.MatchByPath(requestPath);   \/\/ \u0412\u041d\u0418\u041c\u0410\u041d\u0418\u0415: \u043f\u043e \u043f\u0443\u0442\u0438, \u0431\u0435\u0437 \u0443\u0447\u0451\u0442\u0430 \u043c\u0435\u0442\u043e\u0434\u0430var cors = route?.Cors;if (cors is null) { await next(); return; }    \/\/ \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0431\u0435\u0437 CORS \u2014 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u0430<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0438\u0441\u043a\u00a0<strong>\u043f\u043e \u043f\u0443\u0442\u0438, \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044f \u043c\u0435\u0442\u043e\u0434<\/strong>\u00a0\u2014 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b preflight-\u0437\u0430\u043f\u0440\u043e\u0441\u00a0<code>OPTIONS<\/code>\u00a0\u043d\u0430\u0448\u0451\u043b \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438\u00a0<code>OPTIONS<\/code>\u00a0\u043d\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430.<\/p>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u2014 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 origin&#8217;\u0430:<\/p>\n<pre><code>var resolved = ResolveOrigin(cors, ctx.Request, requestOrigin);\/\/ \u0444\u0443\u0442\u0433\u0430\u043d wildcard+credentials: \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043e\u0442\u0432\u0435\u0440\u0433\u043d\u0435\u0442 \u2192 fail closedif (resolved == \"*\" &amp;&amp; cors.AllowCredentials)    resolved = null;if (resolved is not null){    ctx.Response.Headers[\"Access-Control-Allow-Origin\"] = resolved;    AppendVary(ctx.Response.Headers, \"Origin\");   \/\/ \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u0435\u043d, \u0438\u043d\u0430\u0447\u0435 \u043a\u0435\u0448\u0438 \u043f\u0435\u0440\u0435\u043f\u0443\u0442\u0430\u044e\u0442 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438    if (cors.AllowCredentials)        ctx.Response.Headers[\"Access-Control-Allow-Credentials\"] = \"true\";    \/\/ ... preflight-\u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044f \u043d\u0438\u0436\u0435}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>ResolveOrigin<\/code>\u00a0\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u0430\u043a:<\/p>\n<ul>\n<li>\n<p><strong>\u0435\u0441\u0442\u044c \u0440\u0435\u0437\u043e\u043b\u0432\u0435\u0440<\/strong>\u00a0\u2192 \u0435\u0433\u043e \u0441\u043b\u043e\u0432\u043e \u0437\u0430\u043a\u043e\u043d (\u043c\u043e\u0436\u0435\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 origin,\u00a0<code>\"*\"<\/code>\u00a0\u0438\u043b\u0438\u00a0<code>null<\/code>);<\/p>\n<\/li>\n<li>\n<p><strong>\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439\u00a0<\/strong><code><strong>\"*\"<\/strong><\/code>\u00a0\u2192 \u043e\u0442\u0434\u0430\u0451\u043c\u00a0<code>*<\/code>\u00a0\u043a\u0430\u043a \u0435\u0441\u0442\u044c;<\/p>\n<\/li>\n<li>\n<p><strong>\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0431\u0435\u043b\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a<\/strong>\u00a0\u2192 \u043e\u0442\u0440\u0430\u0436\u0430\u0435\u043c\u00a0<code>Origin<\/code>\u00a0\u0437\u0430\u043f\u0440\u043e\u0441\u0430,\u00a0<strong>\u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438<\/strong>\u00a0\u043e\u043d \u0435\u0441\u0442\u044c \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 (\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u044e\u0442 CSV \u0432\u00a0<code>Access-Control-Allow-Origin<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u0438\u043d);<\/p>\n<\/li>\n<li>\n<p>\u0438\u043d\u0430\u0447\u0435 \u2192\u00a0<code>null<\/code>\u00a0(origin \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 CORS \u043d\u0435 \u0441\u0442\u0430\u0432\u044f\u0442\u0441\u044f).<\/p>\n<\/li>\n<\/ul>\n<p><strong>Preflight (OPTIONS).<\/strong>\u00a0\u041d\u0430 preflight \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u043e\u0442\u0440\u0430\u0436\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043d\u044b\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u043c\u0435\u0442\u043e\u0434 \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438:<\/p>\n<pre><code>if (HttpMethods.IsOptions(ctx.Request.Method)){    var requestedMethod = ctx.Request.Headers[\"Access-Control-Request-Method\"].ToString();    ctx.Response.Headers[\"Access-Control-Allow-Methods\"] = !string.IsNullOrEmpty(requestedMethod)        ? requestedMethod : (cors.AllowedMethods ?? route!.Methods ?? \"*\");    var requestedHeaders = ctx.Request.Headers[\"Access-Control-Request-Headers\"].ToString();    ctx.Response.Headers[\"Access-Control-Allow-Headers\"] = !string.IsNullOrEmpty(requestedHeaders)        ? requestedHeaders : (cors.AllowCredentials ? \"Content-Type, Authorization\" : \"*\");    ctx.Response.Headers[\"Access-Control-Max-Age\"] = cors.MaxAgeSeconds.ToString();  \/\/ \u0434\u0435\u0444\u043e\u043b\u0442 86400}\/\/ OPTIONS \u0432\u0441\u0435\u0433\u0434\u0430 \u0437\u0430\u043c\u044b\u043a\u0430\u0435\u0442\u0441\u044f \u043d\u0430 204 \u2014 \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 origin \u043e\u0442\u0432\u0435\u0440\u0433\u043d\u0443\u0442if (HttpMethods.IsOptions(ctx.Request.Method)){    ctx.Response.StatusCode = StatusCodes.Status204NoContent;    return;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u0432\u0435\u0441\u044c CORS \u2014 \u044d\u0442\u043e \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u0430\u044f \u0440\u0443\u0447\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u043e\u0432\u0435\u0440\u0445 Kestrel, \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c\u00a0<code>Vary: Origin<\/code>, \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 preflight \u0438 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 wildcard+credentials. \u041d\u0438\u043a\u0430\u043a\u043e\u0433\u043e\u00a0<code>app.UseCors()<\/code>.<\/p>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 7. \u0421\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u043e\u0442\u0432\u0435\u0442\u0430: SSE \u0438 chunked<\/h3>\n<p>InOut-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0443\u043c\u0435\u0435\u0442 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u0442\u0435\u043b\u043e, \u043d\u043e \u0438\u00a0<strong>\u043f\u043e\u0442\u043e\u043a<\/strong>\u00a0\u2014\u00a0<code>IAsyncEnumerable&lt;string&gt;<\/code>. \u042d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 LLM-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0435 \u0434\u043b\u044f \u0441\u0442\u0440\u0438\u043c\u0430 \u0442\u043e\u043a\u0435\u043d\u043e\u0432. \u041b\u043e\u0433\u0438\u043a\u0430 \u0432\u00a0<code>WriteResponse<\/code>:<\/p>\n<pre><code>else if (body is IAsyncEnumerable&lt;string&gt; asyncStrings){    var useSse = responseContentType?.Contains(\"text\/event-stream\", ...) == true;    httpContext.Response.Headers[\"Cache-Control\"]  = \"no-cache, no-transform\";    httpContext.Response.Headers[\"X-Accel-Buffering\"] = \"no\";   \/\/ \u043d\u0435 \u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 nginx\/LB    httpContext.Features.Get&lt;IHttpResponseBodyFeature&gt;()?.DisableBuffering();  \/\/ \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0431\u0443\u0444\u0435\u0440 ASP.NET    if (useSse)        await WriteSseStreamAsync(...);          \/\/ text\/event-stream \u2192 SSE-\u0444\u0440\u0435\u0439\u043c\u0438\u043d\u0433    else        await WriteChunkedTextStreamAsync(...);  \/\/ \u0438\u043d\u0430\u0447\u0435 \u2192 chunked plain text}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043f\u043e\u0441\u043e\u0431 \u0444\u0440\u0435\u0439\u043c\u0438\u043d\u0433\u0430 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u00a0<strong>Content-Type \u043e\u0442\u0432\u0435\u0442\u0430<\/strong>\u00a0(\u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u043a\u0432\u043e\u0437\u043d\u043e\u0439 \u0441\u0438\u0433\u043d\u0430\u043b\u00a0<code>Accept \u2194 Content-Type<\/code>), \u0430 \u043d\u0435 \u043f\u043e \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u043c\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443:<\/p>\n<ul>\n<li>\n<p><code><strong>text\/event-stream<\/strong><\/code>\u00a0\u2192\u00a0<a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/Server-sent_events\" rel=\"noopener noreferrer nofollow\">Server-Sent Events<\/a>: \u043a\u0430\u0436\u0434\u044b\u0439 yield \u2192 \u043e\u0434\u0438\u043d\u00a0<code>data:<\/code>-\u0444\u0440\u0435\u0439\u043c; \u0432 \u043a\u043e\u043d\u0446\u0435 \u2014\u00a0<code>event: done<\/code>\u00a0\u0441 \u043f\u043e\u0437\u0434\u043d\u0438\u043c\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438-\u0438\u0442\u043e\u0433\u0430\u043c\u0438 (<code>llm.tokens.in\/out<\/code>,\u00a0<code>llm.stop_reason<\/code>\u00a0\u0438 \u0442.\u043f.), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0443\u0436\u0435\u00a0<strong>\u043f\u043e\u0441\u043b\u0435<\/strong>\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435<\/strong>\u00a0\u2192 chunked plain text: \u043a\u0430\u0436\u0434\u044b\u0439 yield = \u043e\u0434\u0438\u043d chunk, \u0441\u00a0<code>FlushAsync<\/code>\u00a0\u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e.<\/p>\n<\/li>\n<\/ul>\n<p><code>DisableBuffering()<\/code>\u00a0\u043a\u0440\u0438\u0442\u0438\u0447\u0435\u043d: \u0431\u0435\u0437 \u043d\u0435\u0433\u043e <a href=\"http:\/\/ASP.NET\" rel=\"noopener noreferrer nofollow\">ASP.NET<\/a> \u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430\u043b \u0431\u044b \u0447\u0430\u043d\u043a\u0438 \u0438 \u043e\u0442\u0434\u0430\u0432\u0430\u043b \u0438\u0445 \u043f\u0430\u0447\u043a\u043e\u0439, \u0443\u0431\u0438\u0432\u0430\u044f \u0432\u0435\u0441\u044c \u0441\u043c\u044b\u0441\u043b \u0441\u0442\u0440\u0438\u043c\u0430.<\/p>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 8. \u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440: HTTP-\u043a\u043b\u0438\u0435\u043d\u0442 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0440\u0443\u0447\u043a\u0430\u043c\u0438<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0430\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u0430 \u2014\u00a0<code>HttpProducer<\/code>\u00a0\u043f\u043e\u0432\u0435\u0440\u0445\u00a0<code>HttpClient<\/code>. \u041a\u043b\u0438\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0432\u00a0<code>ConnectAsync<\/code>:<\/p>\n<pre><code>_handler = new HttpClientHandler{    AllowAutoRedirect = _options.FollowRedirects,        \/\/ followRedirects (\u043f\u043e \u0443\u043c\u043e\u043b\u0447. true)    MaxAutomaticRedirections = _options.MaxRedirects      \/\/ maxRedirects (\u043f\u043e \u0443\u043c\u043e\u043b\u0447. 50)};_httpClient = new HttpClient(_handler){    Timeout = _options.Timeout &gt; 0        ? TimeSpan.FromMilliseconds(_options.Timeout)     \/\/ timeout (\u043f\u043e \u0443\u043c\u043e\u043b\u0447. 30000)        : Timeout.InfiniteTimeSpan};ConfigureAuthentication(_httpClient);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 URL \u2014 \u0447\u0435\u0442\u044b\u0440\u0435 \u0441\u043b\u043e\u044f<\/h4>\n<p><code>ResolveUrl<\/code>\u00a0\u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u0441\u043b\u043e\u0439\u043d\u043e:<\/p>\n<pre><code>\/\/ 1. \u0411\u0430\u0437\u043e\u0432\u044b\u0439 URL \u0438\u0437 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430, \u0441 \u0440\u0435\u0437\u043e\u043b\u0432\u043e\u043c ${...}-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439var baseUrl = _options.ResolveOption(_endpoint.BuildProducerUrl(), exchange) ?? ...;\/\/ 2. \u041f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 {name}-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0438\u0437 .Param(...)baseUrl = ResolveNamedParams(baseUrl, exchange);\/\/ 3. Query-\u0441\u0442\u0440\u043e\u043a\u0430 \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 redbHttp.Query, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044cif (exchange.In.Headers.TryGetValue(\"redbHttp.Query\", out var query) &amp;&amp; query is string qs &amp;&amp; qs.Length &gt; 0){    var sep = baseUrl.Contains('?') ? \"&amp;\" : \"?\";    return $\"{baseUrl}{sep}{qs}\";}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0411\u0430\u0437\u043e\u0432\u044b\u0439 URL \u0441\u0442\u0440\u043e\u0438\u0442\u00a0<code>HttpEndpoint.BuildProducerUrl()<\/code>\u00a0\u2014 \u043f\u0440\u043e\u0441\u0442\u043e\u00a0<code>scheme + host[:port]\/path<\/code>. \u0410\u00a0<code>{name}<\/code>-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441 URL-\u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c:<\/p>\n<pre><code>\/\/ ResolveNamedParamsvar resolved = valueTemplate.Contains(\"${\")    ? (_options.ResolveOption(valueTemplate, exchange) ?? valueTemplate)    : valueTemplate;url = url.Replace($\"{{{name}}}\", Uri.EscapeDataString(resolved), ...);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c:<\/p>\n<pre><code>.To(Http.Get(\"api.example.com\/users\/{id}\/orders\").Param(\"id\", Header(\"userId\")))<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u043d\u0430 \u043b\u0435\u0442\u0443 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u0441\u044f \u0432\u00a0<a href=\"http:\/\/api.example.com\/users\/42\/orders\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/api.example.com\/users\/42\/orders<\/code><\/a>, \u0433\u0434\u0435\u00a0<code>42<\/code>\u00a0\u0432\u0437\u044f\u0442\u043e \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u00a0<code>userId<\/code>\u00a0\u0438 \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043e.<\/p>\n<h4>\u041c\u0435\u0442\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/h4>\n<p>\u041c\u0435\u0442\u043e\u0434 \u0431\u0435\u0440\u0451\u0442\u0441\u044f \u0438\u0437 \u043e\u043f\u0446\u0438\u0439 (<code>?method=POST<\/code>), \u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c\u00a0<strong>\u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c<\/strong>\u00a0<code>redbHttp.Method<\/code>:<\/p>\n<pre><code>if (exchange.In.Headers.TryGetValue(\"redbHttp.Method\", out var hm) &amp;&amp; hm is string methodStr)    return new SysHttpMethod(methodStr.ToUpperInvariant());<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043b\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f\u00a0<code>POST\/PUT\/PATCH<\/code>\u00a0(<code>HasBody<\/code>).\u00a0<code>byte[]<\/code>\u00a0\u2192\u00a0<code>ByteArrayContent<\/code>,\u00a0<code>Stream<\/code>\u00a0\u2192\u00a0<code>StreamContent<\/code>, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u2192\u00a0<code>StringContent<\/code>\u00a0\u0432 UTF-8.<\/p>\n<h4>\u0411\u0440\u0438\u0434\u0436\u0438\u043d\u0433 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432<\/h4>\n<p>\u041f\u0440\u0438\u00a0<code>bridgeHeaders=true<\/code>\u00a0(\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e) \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438\u00a0<code>Exchange<\/code>\u00a0\u0443\u0435\u0437\u0436\u0430\u044e\u0442 \u0432 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441 \u2014 \u043a\u0440\u043e\u043c\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0438 hop-by-hop (<code>NonBridgedHeaders<\/code>):<\/p>\n<pre><code>foreach (var (key, value) in exchange.In.Headers){    if (value is null) continue;    if (HttpHeaders.NonBridgedHeaders.Contains(key)) continue;  \/\/ Connection, TE, redbHttp.*, Content-* \u0438 \u0442.\u043f.    if (!request.Headers.TryAddWithoutValidation(key, strValue))        request.Content?.Headers.TryAddWithoutValidation(key, strValue);  \/\/ \u0438\u043d\u0430\u0447\u0435 \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043a\u0430\u043a content-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>NonBridgedHeaders<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445\u00a0<code>redbHttp.*<\/code>, hop-by-hop (<code>Connection<\/code>,\u00a0<code>Keep-Alive<\/code>,\u00a0<code>Transfer-Encoding<\/code>,\u00a0<code>TE<\/code>,\u00a0<code>Trailer<\/code>,\u00a0<code>Upgrade<\/code>,\u00a0<code>Proxy-*<\/code>) \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445\u00a0<code>HttpClient<\/code>\u00a0content-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 (<code>Content-Type<\/code>,\u00a0<code>Content-Length<\/code>,\u00a0<code>Content-Encoding<\/code>\u2026).<\/p>\n<h4>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/h4>\n<p>\u0422\u0440\u0438 \u0441\u0445\u0435\u043c\u044b (<code>HttpAuthScheme<\/code>):<\/p>\n<ul>\n<li>\n<p><strong>Basic<\/strong>\u00a0\u2014\u00a0<code>username<\/code>\/<code>password<\/code>, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a\u00a0<code>Authorization: Basic ...<\/code>\u00a0\u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442.<\/p>\n<\/li>\n<li>\n<p><strong>Bearer \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439<\/strong>\u00a0\u2014 \u0442\u043e\u043a\u0435\u043d-\u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430, \u0442\u043e\u0436\u0435 \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442.<\/p>\n<\/li>\n<li>\n<p><strong>Bearer \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439<\/strong>\u00a0\u2014 \u0442\u043e\u043a\u0435\u043d-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 (<code>DynamicValue&lt;string&gt;.IsDynamic<\/code>), \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u0441\u044f\u00a0<strong>\u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441<\/strong>\u00a0\u0438\u0437\u00a0<code>Exchange<\/code>:<\/p>\n<\/li>\n<\/ul>\n<pre><code>\/\/ ConfigurePerRequestAuthif (_options.AuthScheme == HttpAuthScheme.Bearer &amp;&amp; _options.AuthToken.Value.IsDynamic){    var token = _options.AuthToken.Value.Resolve(exchange);    if (!string.IsNullOrEmpty(token))        request.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", token);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c\u00a0<code>.BearerAuth().AuthToken(Header(\"jwt\"))<\/code>\u00a0\u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u0442 \u0441\u0432\u0435\u0436\u0438\u0439 JWT \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0432\u044b\u0437\u043e\u0432.<\/p>\n<h4>\u041e\u0442\u0432\u0435\u0442 \u2192\u00a0Exchange<\/h4>\n<p><code>MapResponse<\/code>\u00a0\u043a\u043b\u0430\u0434\u0451\u0442 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0432\u00a0<code>Out<\/code>\u00a0\u0438 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438:<\/p>\n<pre><code>outMessage.Headers[\"redbHttp.StatusCode\"] = (int)response.StatusCode;outMessage.Headers[\"redbHttp.StatusText\"] = response.ReasonPhrase ?? \"\";outMessage.Headers[\"redbHttp.Url\"]        = response.RequestMessage?.RequestUri?.ToString() ?? \"\";<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u0438\u00a0<code>copyResponseHeaders=true<\/code>\u00a0(\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e) \u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430, \u0438\u00a0<code>Content-Type<\/code>\/<code>Content-Length<\/code>. \u041f\u0440\u0438\u00a0<code>streamResponse=true<\/code>\u00a0\u0442\u0435\u043b\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f\u00a0<code>Stream<\/code>, \u0430 \u043d\u0435\u00a0<code>byte[]<\/code>\u00a0\u2014 \u0438 \u0442\u043e\u0433\u0434\u0430\u00a0<code>HttpResponseMessage<\/code>\u00a0\u043d\u0430\u043c\u0435\u0440\u0435\u043d\u043d\u043e\u00a0<strong>\u043d\u0435<\/strong>\u00a0\u0434\u0438\u0441\u043f\u043e\u0437\u0438\u0442\u0441\u044f \u0441\u0440\u0430\u0437\u0443: \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043a\u0440\u043e\u0435\u0442\u00a0<code>Exchange.DisposeAsync<\/code>.<\/p>\n<h4>throwOnError<\/h4>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e\u00a0<code>throwOnError=true<\/code>\u00a0\u2014 \u043d\u0430\u00a0<code>4xx\/5xx<\/code>\u00a0\u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 \u0431\u0440\u043e\u0441\u0430\u0435\u0442\u00a0<code>HttpRequestException<\/code>\u00a0(\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u0438\u0442 \u0432\u0430\u0448\u00a0<code>OnException<\/code>\/<code>TryCatch<\/code>). \u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f\u00a0<code>.NoThrowOnError()<\/code>, \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0437\u0440\u0443\u043b\u0438\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0447\u0435\u0440\u0435\u0437\u00a0<code>${header.redbHttp.StatusCode}<\/code>.<\/p>\n<hr\/>\n<h3>\u0427\u0430\u0441\u0442\u044c 9. \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0451 \u0432\u043c\u0435\u0441\u0442\u0435 \u2014 \u0431\u043e\u0435\u0432\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442<\/h3>\n<p>\u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a\u00a0<code>MainPipelineRoutes.cs<\/code>\u00a0\u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043f\u043e\u043b\u043d\u044b\u0439 HTTP-\u0432\u0445\u043e\u0434 \u0441 Content-Based Router \u0438 request\/reply (<code>redb.Route.Demo<\/code>):<\/p>\n<pre><code>From(\"http:0.0.0.0:5088\/api\/demo?inOut=true\")    .RouteId(\"demo-http-entry\")    .ConvertBody&lt;string&gt;()              \/\/ byte[] \u2192 string    .Throttle(10)                       \/\/ \u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 10 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\/\u0441\u0435\u043a    .Log(\"[1-HTTP] \u25b6 body=${body}, contentType=${contentType}\")    .SetHeader(\"traceId\", e =&gt; Guid.NewGuid().ToString(\"N\")[..12])    .Log(\"[1-HTTP]   traceId=${header.traceId}, mode=${header.mode}\")    .ValidateJsonSchema(MessageSchema)  \/\/ \u0442\u0435\u043b\u043e \u2014 JSON \u0441 \u043f\u043e\u043b\u0435\u043c \"message\"    .IdempotentConsumer(e =&gt; GetHeader(e, \"traceId\") ?? \"\", IdempotentRepo)    \/\/ \u2500\u2500 Content-Based Router: \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443 mode \u2500\u2500    .Choice()        .When(e =&gt; GetHeader(e, \"mode\") == \"full\")            .SetHeader(\"fastTrack\", e =&gt; GetHeader(e, \"priority\") == \"high\" ? \"true\" : \"false\")            .SetHeader(\"stamp.dsl\", \"full-branch\")        .When(e =&gt; GetHeader(e, \"mode\") == \"short\")            .SetHeader(\"fastTrack\", \"false\")            .SetHeader(\"stamp.dsl\", \"short-branch\")        .Otherwise()            .SetHeader(\"mode\", \"default\")            .SetHeader(\"stamp.dsl\", \"default-branch\")    .EndChoice()    \/\/ ... \u0442\u0443\u0442 \u0432 \u0434\u0435\u043c\u043e \u2014 \u043a\u0440\u043e\u0441\u0441-\u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u044b\u0439 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440, SQL, WireTap'\u044b ...    .SetHeader(\"Content-Type\", \"application\/json\")    .SetBody(e =&gt; BuildResponse(e));     \/\/ inOut=true \u2192 \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0451\u0440\u0433\u0430\u0435\u043c \u0442\u0440\u0435\u043c\u044f curl&#8217;\u0430\u043c\u0438 \u2014 \u0442\u0440\u0438 \u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0435\u0442\u043a\u0438:<\/p>\n<pre><code class=\"bash\"># full-branchcurl -X POST http:\/\/localhost:5088\/api\/demo \\  -H \"Content-Type: application\/json\" -H \"mode: full\" -H \"priority: high\" \\  -d '{\"message\":\"hello\"}'# short-branchcurl -X POST http:\/\/localhost:5088\/api\/demo \\  -H \"Content-Type: application\/json\" -H \"mode: short\" \\  -d '{\"message\":\"hi\"}'# default-branch (mode \u043d\u0435 \u0437\u0430\u0434\u0430\u043d)curl -X POST http:\/\/localhost:5088\/api\/demo \\  -H \"Content-Type: application\/json\" \\  -d '{\"message\":\"yo\"}'<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410 \u0440\u044f\u0434\u043e\u043c, \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 \u043f\u043e\u0440\u0442\u0443 5088, \u0436\u0438\u0432\u0451\u0442 echo-\u043c\u0430\u0440\u0448\u0440\u0443\u0442 (<code>EchoRoutes.cs<\/code>) \u2014 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439\u00a0<code>From<\/code>, \u043e\u0431\u0449\u0438\u0439 Kestrel:<\/p>\n<pre><code>From(\"http:0.0.0.0:5088\/api\/echo?inOut=true\")    .RouteId(\"demo-http-echo\")    .AutoStart(false)                    \/\/ \u0434\u0440\u0435\u043c\u043b\u0435\u0442, \u043f\u043e\u043a\u0430 \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0448\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e    .ConvertBody&lt;string&gt;()    .SetHeader(\"Content-Type\", e =&gt; \/* \u043e\u0442\u0440\u0430\u0436\u0430\u0435\u043c Content-Type \u0437\u0430\u043f\u0440\u043e\u0441\u0430 *\/ ...)    .Log(\"[ECHO] \u25c0 Echoing back: ${body}\");<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>.AutoStart(false)<\/code>\u00a0\u2014 \u043e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0438\u0437 \u0447\u0430\u0441\u0442\u0438 4: \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d, \u043d\u043e \u043d\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 \u0441 \u043c\u043e\u0434\u0443\u043b\u0435\u043c. \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0435\u0433\u043e \u0440\u0443\u043a\u0430\u043c\u0438 (<code>tsak route start demo-http-echo<\/code>) \u2014 \u043e\u043d \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u00a0<strong>\u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u043c<\/strong>\u00a0Kestrel \u043f\u043e\u0440\u0442\u0430 5088. \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u2014 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043f\u043e\u0433\u0430\u0441\u043d\u0435\u0442, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0<code>\/api\/demo<\/code>\u00a0\u0432\u0441\u0451 \u0435\u0449\u0451 \u0441\u043b\u0443\u0448\u0430\u0435\u0442.<\/p>\n<hr\/>\n<h3>\u0428\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0430 \u043f\u043e \u0433\u0440\u0430\u0431\u043b\u044f\u043c<\/h3>\n<ul>\n<li>\n<p><strong>\u041d\u0435\u0442 \u0442\u0435\u043b\u0430 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435?<\/strong>\u00a0\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435\u00a0<code>inOut=true<\/code>. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u043e\u0442\u0434\u0430\u0451\u0442 \u043f\u0443\u0441\u0442\u043e\u0439\u00a0<code>200 OK<\/code>, \u0447\u0442\u043e \u0431\u044b \u0432\u044b \u043d\u0438 \u0434\u0435\u043b\u0430\u043b\u0438 \u0441\u00a0<code>.SetBody(...)<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>CORS \u00ab\u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u00bb?<\/strong>\u00a0\u041f\u0440\u0438\u00a0<code>cors=true<\/code>\u00a0\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u0435\u043d\u00a0<code>corsOrigins<\/code>\u00a0(\u0438\u043b\u0438 \u0440\u0435\u0437\u043e\u043b\u0432\u0435\u0440) \u2014 \u0438\u043d\u0430\u0447\u0435 \u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435. Wildcard\u00a0<code>*<\/code>\u00a0+ credentials \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043e\u0442\u0432\u0435\u0440\u0433\u0430\u0435\u0442, \u0438 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0447\u0435\u0441\u0442\u043d\u043e \u043e\u0442\u0434\u0430\u0451\u0442 \u043e\u0442\u0432\u0435\u0442 \u0431\u0435\u0437 CORS-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 (fail closed).<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0440\u0442 \u0437\u0430\u043d\u044f\u0442?<\/strong>\u00a0\u0412 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 Kestrel \u0448\u0430\u0440\u0438\u0442\u0441\u044f \u043f\u043e\u00a0<code>(host, port)<\/code>\u00a0\u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u00a0<code>SharedHttpServerManager<\/code>\u00a0\u2014 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u0440\u0442\u0443 \u0434\u0435\u043b\u044f\u0442 \u043e\u0434\u0438\u043d \u0441\u0435\u0440\u0432\u0435\u0440 (\u0432 Tsak \u043c\u043e\u0436\u043d\u043e \u0441\u0435\u0441\u0442\u044c \u0434\u0430\u0436\u0435 \u043d\u0430 \u043f\u043e\u0440\u0442 \u0441\u0430\u043c\u043e\u0439 \u0430\u0434\u043c\u0438\u043d\u043a\u0438). \u041a\u043e\u043d\u0444\u043b\u0438\u043a\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0440\u0442 \u0437\u0430\u043d\u044f\u043b\u00a0<strong>\u0447\u0443\u0436\u043e\u0439<\/strong>, \u043d\u0435-redb \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0440\u043e\u0442\u0435\u043a\u0430\u044e\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442?<\/strong>\u00a0\u041d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u2014 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0438\u0445 \u0442\u0440\u0435\u043a\u0430\u0435\u0442 (<code>RequestHeaderNames<\/code>) \u0438 \u043d\u0435 \u043e\u0442\u0440\u0430\u0436\u0430\u0435\u0442. \u041d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0441\u0430\u043c\u0438 \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441 \u0442\u0435\u043c \u0436\u0435 \u0438\u043c\u0435\u043d\u0435\u043c \u2014 \u043e\u043d \u043f\u043e\u043f\u0430\u0434\u0451\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u0442\u0440\u0438\u043c \u043e\u0442\u0434\u0430\u0451\u0442\u0441\u044f \u043f\u0430\u0447\u043a\u043e\u0439?<\/strong>\u00a0\u0414\u043b\u044f SSE \u043d\u0443\u0436\u0435\u043d\u00a0<code>Content-Type: text\/event-stream<\/code>\u00a0\u043d\u0430 \u043e\u0442\u0432\u0435\u0442\u0435; \u0438\u043d\u0430\u0447\u0435 \u0431\u0443\u0434\u0435\u0442 chunked plain text. \u0411\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p><code><strong>{id}<\/strong><\/code><strong>\u00a0\u043d\u0435 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u043b\u0441\u044f \u0443 \u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u0430?<\/strong>\u00a0\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437\u00a0<code>.Param(\"id\", ...)<\/code>; \u0431\u0435\u0437\u00a0<code>.Param<\/code>\u00a0\u043f\u043b\u0435\u0439\u0441\u0445\u043e\u043b\u0434\u0435\u0440\u00a0<code>{id}<\/code>\u00a0\u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0432 URL \u043a\u0430\u043a \u0435\u0441\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p><strong>405 \u0432\u043c\u0435\u0441\u0442\u043e 404?<\/strong>\u00a0\u042d\u0442\u043e \u0444\u0438\u0447\u0430: \u043f\u0443\u0442\u044c \u043d\u0430\u0448\u0451\u043b\u0441\u044f, \u043c\u0435\u0442\u043e\u0434 \u2014 \u043d\u0435\u0442. \u0421\u0443\u0437\u044c\u0442\u0435\u00a0<code>methods=<\/code>\u00a0\u0438\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435, \u043a\u0430\u043a\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0441\u0442\u0443\u0447\u0438\u0442\u0435\u0441\u044c.<\/p>\n<\/li>\n<\/ul>\n<hr\/>\n<h3>\u0418\u0442\u043e\u0433\u043e<\/h3>\n<p><code>redb.Route.Http<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043d\u0435 \u00ab\u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c\u00bb, \u0430 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442:<\/p>\n<ul>\n<li>\n<p><strong>\u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440<\/strong>\u00a0\u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 Kestrel (<code>CreateSlimBuilder<\/code>, \u0431\u0435\u0437 MVC), \u0448\u0430\u0440\u0438\u0442 \u0435\u0433\u043e \u043c\u0435\u0436\u0434\u0443 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c\u0438 \u043f\u043e\u00a0<code>(host, port)<\/code>\u00a0\u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u00a0<code>SharedHttpServerManager<\/code>, \u0432\u0435\u0434\u0451\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u043e\u0441\u0442\u044c\u044e, \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u0434\u043b\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 CORS \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u2014 \u043f\u043e \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0435 \u043d\u0430 \u043c\u0430\u0440\u0448\u0440\u0443\u0442.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440<\/strong>\u00a0\u2014 \u044d\u0442\u043e\u00a0<code>HttpClient<\/code>\u00a0\u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0440\u0443\u0447\u043a\u0430\u043c\u0438: \u043f\u043e\u0441\u043b\u043e\u0439\u043d\u043e\u0435 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 URL,\u00a0<code>{name}<\/code>-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0431\u0440\u0438\u0434\u0436\u0438\u043d\u0433 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432, Basic\/Bearer (\u0432 \u0442.\u0447. \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439 per-request \u0442\u043e\u043a\u0435\u043d), \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439\u00a0<code>throwOnError<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>HTTP \u2194 Exchange<\/strong>\u00a0\u2014 \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0439 \u043c\u043e\u0441\u0442 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438\u00a0<code>redbHttp.*<\/code>, \u0441 \u0447\u0435\u0441\u0442\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, route-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0441\u0442\u0430\u0442\u0443\u0441-\u043a\u043e\u0434\u043e\u0432 \u0438 \u0431\u0435\u0437\u0442\u0435\u043b\u0435\u0441\u043d\u044b\u0445 \u043e\u0442\u0432\u0435\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u00a0<strong>Content-Based Router<\/strong>\u00a0(<code>.Choice().When().Otherwise()<\/code>) \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0440\u0430\u0434\u0438 \u0447\u0435\u0433\u043e \u0432\u0441\u0451 \u044d\u0442\u043e: \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443 \u0443\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0434 \u043d\u0438\u043c \u2014 Kestrel, Kafka \u0438\u043b\u0438 RabbitMQ.<\/p>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0435\u0440\u0438\u0438 \u0431\u0435\u0440\u0451\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 EIP. \u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u2014 \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445.<\/p>\n<hr\/>\n<blockquote>\n<p><strong>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d \u043f\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c<\/strong>\u00a0<code>redb.Route\/src\/redb.Route.Http<\/code>\u00a0(<code>HttpConsumer<\/code>,\u00a0<code>HttpProducer<\/code>,\u00a0<code>HttpComponent<\/code>,\u00a0<code>SharedHttpServerManager<\/code>,\u00a0<code>HttpEndpointOptions<\/code>,\u00a0<code>HttpHeaders<\/code>,\u00a0<code>Fluent\/HttpDsl<\/code>) \u0438\u00a0<code>redb.Route.Controllers<\/code>. \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u2014 \u0438\u0437 \u0434\u0435\u043c\u043e-\u043f\u0440\u043e\u0435\u043a\u0442\u0430\u00a0<code>redb.Route.Demo\/Routes<\/code>\u00a0(<code>MainPipelineRoutes<\/code>,\u00a0<code>EchoRoutes<\/code>,\u00a0<code>DataObservabilityRoutes<\/code>) \u0438 \u0438\u0437\u00a0<strong>\u0431\u043e\u0435\u0432\u043e\u0433\u043e<\/strong>\u00a0\u043a\u043e\u0434\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u044b TsUM (<code>tsum.Api\/Routes<\/code>,\u00a0<code>tsum.Api\/Auth<\/code>) \u2014 \u0442\u0435 \u0436\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b \u043a\u0440\u0443\u0442\u044f\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0434\u0435 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 5090. \u0420\u0430\u0437\u0434\u0435\u043b \u043f\u0440\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d \u043f\u0440\u043e\u0434\u043e\u043c: \u0432\u0441\u044f REST-\u0430\u0434\u043c\u0438\u043d\u043a\u0430 Tsak (<code>redb.Tsak.Core\/Controllers<\/code>\u00a0\u2014\u00a0<code>Contexts<\/code>,\u00a0<code>Routes<\/code>,\u00a0<code>Modules<\/code>,\u00a0<code>Auth<\/code>,\u00a0<code>Users<\/code>, \u2026 \u2014 ~14 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432) \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043d\u0430\u00a0<code>RedbController<\/code>\u00a0\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043f\u0440\u043e\u0434\u0435 \u0447\u0435\u0440\u0435\u0437\u00a0<code>ControllerDispatcherProcessor<\/code>. \u0412 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u043c TsUM-API \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u043b\u0438\u00a0<code>.Process<\/code>\/<code>.Choice<\/code>\u00a0\u2014 \u043e\u0431\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0436\u0438\u0432\u0443\u0442 \u0440\u044f\u0434\u043e\u043c \u0438 \u043e\u0431\u0430 \u0431\u043e\u0435\u0432\u044b\u0435.<\/p>\n<\/blockquote>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1049222\/\">https:\/\/habr.com\/ru\/articles\/1049222\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>redb route http chise when\u0421\u0435\u0440\u0438\u044f:\u00a0redb ecosystem \/ redb.Route deep-dive\u0412\u00a0redb.Route\u00a0\u2014 \u043d\u0430\u0448\u0435\u043c ESB \u0432 \u0441\u0442\u0438\u043b\u0435\u00a0Apache Camel\u00a0\u043f\u043e\u0434 .NET \u2014 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0432\u0441\u0435\u0433\u0434\u0430 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e:\u00a0From(\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a) \u2192 [\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b] \u2192 To(\u043f\u0440\u0438\u0451\u043c\u043d\u0438\u043a). \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0431\u0435\u0440\u0451\u043c\u00a0\u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438\u00a0\u0438\u00a0\u043e\u0434\u0438\u043d \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u00a0\u0438 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0431\u0430 \u0434\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u0434\u043d\u0430.\u041f\u0430\u0442\u0442\u0435\u0440\u043d:\u00a0Content-Based Router\u00a0\u2014 \u00ab\u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443\u00bb. \u0421\u0430\u043c\u044b\u0439 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0438\u0437 routing-\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432\u00a0\u0425\u043e\u043f\u0435 \u0438 \u0412\u0443\u043b\u044c\u0444\u0430: \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u0440\u0435\u0448\u0438\u0442\u044c, \u043a\u0443\u0434\u0430 \u043e\u043d\u043e \u043f\u043e\u0435\u0434\u0435\u0442 \u0434\u0430\u043b\u044c\u0448\u0435. \u0412 DSL \u044d\u0442\u043e\u00a0.Choice().When(&#8230;).Otherwise().\u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440:\u00a0redb.Route.Http\u00a0\u2014 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 HTTP\/HTTPS. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u044d\u0442\u043e\u00a0\u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u00a0(HTTP-\u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430\u00a0HttpClient), \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u2014\u00a0\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u00a0(\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430\u00a0Kestrel). \u0411\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432, \u0431\u0435\u0437\u00a0[ApiController], \u0431\u0435\u0437 middleware-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 ASP.NET, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u043f\u0438\u0448\u0435\u0442\u0435 \u0440\u0443\u043a\u0430\u043c\u0438.\u0421\u0442\u0430\u0442\u044c\u044f \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0438 \u0431\u043e\u043b\u044c\u0448\u0430\u044f. \u0415\u0441\u043b\u0438 \u0432\u044b \u0436\u0434\u0451\u0442\u0435 \u00abhello world \u0437\u0430 5 \u0441\u0442\u0440\u043e\u043a\u00bb \u2014 \u043e\u043d \u0431\u0443\u0434\u0435\u0442, \u043d\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u043c\u044b \u0432\u043b\u0435\u0437\u0430\u0435\u043c \u0432 \u0442\u043e, \u043a\u0430\u043a \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0432\u043d\u0443\u0442\u0440\u0438: \u043a\u0430\u043a \u043e\u0434\u0438\u043d Kestrel \u0448\u0430\u0440\u0438\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c\u0438, \u043a\u0430\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432\u00a0Exchange\u00a0\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 CORS \u043d\u0430 \u043e\u0431\u0449\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043e \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433\u043e\u043c \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0432 \u043a\u043e\u0434\u0435 \u043d\u0435\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e\u00a0app.UseCors().\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d \u043f\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c\u00a0redb.Route\/src\/redb.Route.Http, \u0432\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u2014 \u0438\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e\u00a0redb.Route.Demo.\u0427\u0430\u0441\u0442\u044c 0. \u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u0451 \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f\u0412\u043e\u0437\u044c\u043c\u0451\u043c \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0451\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443: HTTP-\u0448\u043b\u044e\u0437. \u0421\u043d\u0430\u0440\u0443\u0436\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u00a0POST \/api\/demo, \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u044b:\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0442\u0435\u043b\u043e,\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a\u00a0mode\u00a0\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0435\u0433\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0435\u0442\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u2014 \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c Content-Based Router;\u043e\u0442\u0432\u0435\u0447\u0430\u0435\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0442\u0435\u043c \u0436\u0435 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c (request\/reply).\u0412\u043e\u0442 \u0441\u043a\u0435\u043b\u0435\u0442 (\u043f\u043e\u043b\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0432 \u043a\u043e\u043d\u0446\u0435),\u00a0redb.Route.Demo\/Routes\/MainPipelineRoutes.cs:From(&#171;http:0.0.0.0:5088\/api\/demo?inOut=true&#187;)    .RouteId(&#171;demo-http-entry&#187;)    .ConvertBody&lt;string&gt;()    .Choice()        .When(e =&gt; GetHeader(e, &#171;mode&#187;) == &#171;full&#187;)            .SetHeader(&#171;stamp.dsl&#187;, &#171;full-branch&#187;)        .When(e =&gt; GetHeader(e, &#171;mode&#187;) == &#171;short&#187;)            .SetHeader(&#171;stamp.dsl&#187;, &#171;short-branch&#187;)        .Otherwise()            .SetHeader(&#171;mode&#187;, &#171;default&#187;)            .SetHeader(&#171;stamp.dsl&#187;, &#171;default-branch&#187;)    .EndChoice()    .SetHeader(&#171;Content-Type&#187;, &#171;application\/json&#187;)    .SetBody(e =&gt; BuildResponse(e));\u041e\u0434\u0438\u043d\u00a0From\u00a0\u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 5088, \u043e\u0434\u0438\u043d\u00a0.Choice()\u00a0\u0440\u0435\u0448\u0430\u0435\u0442 \u0441\u0443\u0434\u044c\u0431\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u0434\u0438\u043d\u00a0.SetBody(&#8230;)\u00a0\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043e\u0442\u0432\u0435\u0442. \u0414\u0430\u043b\u044c\u0448\u0435 \u2014 \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.\u0427\u0430\u0441\u0442\u044c 1. Content-Based Router \u2014 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u0447\u0435\u0441\u0442\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440\u0427\u0442\u043e \u044d\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0442\u0430\u043a\u043e\u0435Content-Based Router \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441:\u00a0\u00ab\u043a\u0443\u0434\u0430 \u0434\u0430\u043b\u044c\u0448\u0435?\u00bb\u00a0\u2014 \u0433\u043b\u044f\u0434\u044f \u0432 \u0441\u0430\u043c\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0430 \u043d\u0435 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u044e\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e. \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u043a\u043d\u0438\u0433\u0438: \u0437\u0430\u043a\u0430\u0437\u044b \u0441\u00a0region=EU\u00a0\u0435\u0434\u0443\u0442 \u0432 \u043e\u0434\u0438\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a,\u00a0region=US\u00a0\u2014 \u0432 \u0434\u0440\u0443\u0433\u043e\u0439, \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u2014 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.\u0412 redb.Route \u044d\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u00a0ChoiceProcessor\u00a0(\u0441\u043c.\u00a0redb.Route\/src\/redb.Route\/Processors\/ChoiceProcessor.cs), \u0430 \u0432 DSL \u2014 \u0431\u043b\u043e\u043a\u00a0.Choice():.Choice()    .When(&lt;\u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442&gt;)   \/\/ \u0432\u0435\u0442\u043a\u0430 1        &#8230;processors&#8230;    .When(&lt;\u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442&gt;)   \/\/ \u0432\u0435\u0442\u043a\u0430 2        &#8230;processors&#8230;    .Otherwise()        \/\/ \u0432\u0435\u0442\u043a\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430)        &#8230;processors&#8230;.EndChoice()\u0421\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0430 \u0440\u043e\u0432\u043d\u043e \u043a\u0430\u043a \u0432\u00a0switch: \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442\u0441\u044f\u00a0\u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f\u00a0\u043f\u0435\u0440\u0432\u0430\u044f\u00a0\u0432\u0435\u0442\u043a\u0430, \u0447\u0435\u0439 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442 \u0432\u0435\u0440\u043d\u0443\u043b\u00a0true, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u043d\u0438 \u043e\u0434\u043d\u0430 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0438 \u0435\u0441\u0442\u044c\u00a0.Otherwise()\u00a0\u2014 \u0438\u0434\u0451\u0442 \u043e\u043d\u0430; \u0435\u0441\u043b\u0438\u00a0.Otherwise()\u00a0\u043d\u0435\u0442 \u2014 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0431\u043b\u043e\u043a \u043d\u0430\u0441\u043a\u0432\u043e\u0437\u044c \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.\u0414\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0437\u0430\u0434\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u04421. \u041b\u044f\u043c\u0431\u0434\u0430\u00a0\u2014 \u043a\u043e\u0433\u0434\u0430 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u044c \u043a\u043e\u0434\u043e\u043c:.Choice()    .When(e =&gt; GetHeader(e, &#171;mode&#187;) == &#171;full&#187;)  &#8230;    .When(e =&gt; GetHeader(e, &#171;mode&#187;) == &#171;short&#187;) &#8230;    .Otherwise() &#8230;.EndChoice()2. Fluent-\u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442\u044b \u043f\u043e\u0432\u0435\u0440\u0445 expression-\u0434\u0432\u0438\u0436\u043a\u0430\u00a0\u2014 \u043a\u043e\u0433\u0434\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438. \u0418\u0437\u00a0redb.Route.Demo\/Routes\/DataObservabilityRoutes.cs:.Choice()    .When(Header(&#171;amount&#187;).isGreaterThanOrEqualTo(1000).Matches, w =&gt; w        .SetHeader(&#171;tier&#187;, &#171;gold&#187;))    .When(Header(&#171;amount&#187;).isBetween(500, 999).Matches, w =&gt; w        .SetHeader(&#171;tier&#187;, &#171;silver&#187;))    .When(Header(&#171;amount&#187;).isLessThan(500).Matches, w =&gt; w        .SetHeader(&#171;tier&#187;, &#171;bronze&#187;))    .Otherwise(o =&gt; o        .SetHeader(&#171;tier&#187;, &#171;unknown&#187;))Header(&#171;amount&#187;).isBetween(500, 999)\u00a0\u2014 \u044d\u0442\u043e \u043d\u0435 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435, \u0430 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439\u00a0IPredicate, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u0435\u043b\u0435\u0433\u0430\u0442. \u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u2014 \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0439 expression-\u0434\u0432\u0438\u0436\u043e\u043a \u0441\u0435\u0440\u0438\u0438 (Tokenizer \u2192 Parser \u2192 AST \u2192 System.Linq.Expressions \u2192 IL), \u043d\u043e \u044d\u0442\u043e \u0442\u0435\u043c\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.\u041f\u043e\u0447\u0435\u043c\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u0441 HTTPContent-Based Router \u0438 HTTP-\u0448\u043b\u044e\u0437 \u2014 \u043f\u0430\u0440\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0430\u044f \u0434\u0440\u0443\u0433 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0430. \u041d\u0430 \u0432\u0445\u043e\u0434\u0435 HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438\u00a0Exchange\u00a0(\u043e\u0431 \u044d\u0442\u043e\u043c \u043d\u0438\u0436\u0435): \u043c\u0435\u0442\u043e\u0434, \u043f\u0443\u0442\u044c, query-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, route-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0432\u0441\u0435 HTTP-\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438. \u041b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043d\u0438\u0445 \u2014 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0434\u043b\u044f\u00a0.When(&#8230;):.Choice()    .When(e =&gt; GetHeader(e, &#171;redbHttp.Method&#187;) == &#171;DELETE&#187;)  &#8230; \/\/ \u043f\u043e \u043c\u0435\u0442\u043e\u0434\u0443    .When(e =&gt; GetHeader(e, &#171;X-Tenant&#187;) == &#171;acme&#187;)           &#8230; \/\/ \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443    .When(e =&gt; GetHeader(e, &#171;redbHttp.QueryParam.debug&#187;) == &#171;1&#187;) &#8230; \/\/ \u043f\u043e query.EndChoice()\u041c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440 \u043d\u0435 \u043b\u0435\u0437\u0435\u0442 \u0432 HTTP \u0441\u0430\u043c \u2014 \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0443\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u00a0Exchange. \u042d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0441\u043c\u044b\u0441\u043b \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430: \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043e \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u043b\u0438.\u041f\u0440\u044f\u043c\u043e \u0438\u0437 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0430\u0412\u043e\u0442\u00a0\u0431\u043e\u0435\u0432\u043e\u0439\u00a0\u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0438\u0437 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d-\u0441\u0438\u0441\u0442\u0435\u043c\u044b TsUM (\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438), \u043e\u0434\u0438\u043d-\u0432-\u043e\u0434\u0438\u043d. HTTP-\u0432\u0445\u043e\u0434 + Content-Based Router \u043f\u043e \u043c\u0435\u0442\u043e\u0434\u0443 \u2014 GET \u0438 POST \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u043f\u0443\u0442\u0438 \u0440\u0430\u0437\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0440\u0430\u0437\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438:From(&#171;http:0.0.0.0:5090\/api\/tsum\/user-filters?inOut=true&amp;cors=true&amp;corsOrigins=*&#187;)    .RouteId(&#171;tsum-api-user-filters&#187;)    .Process(Auth.ProcessAsync)                 \/\/ JWT-\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2014 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440    .ConvertBody&lt;string&gt;()    .Choice()        .When(e =&gt; e.In.Headers.TryGetValue(&#171;redbHttp.Method&#187;, out var m) &amp;&amp; m?.ToString() == &#171;POST&#187;)            .ProcessWithRedb((redb, exchange, ct) =&gt; HandlePost(redb, exchange))        .Otherwise()            .ProcessWithRedb((redb, exchange, ct) =&gt; HandleGet(redb, exchange))    .EndChoice();\u0417\u0434\u0435\u0441\u044c \u0432\u0438\u0434\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u0432\u0441\u0451, \u043e \u0447\u0451\u043c \u043f\u043e\u0439\u0434\u0451\u0442 \u0440\u0435\u0447\u044c \u0434\u0430\u043b\u044c\u0448\u0435: HTTP-\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 5090 (inOut=true,\u00a0cors=true&amp;corsOrigins=*), Content-Based Router \u043f\u043e\u00a0redbHttp.Method, \u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043a\u0430\u043a\u00a0\u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u00a0\u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u2014 \u043d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0[Authorize]-\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432. \u0414\u0430\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c, \u043a\u0430\u043a \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u0443\u0441\u043e\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u043d\u0443\u0442\u0440\u0438.tsak \u0427\u0430\u0441\u0442\u044c 2. HTTP-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440: \u0441 \u0432\u044b\u0441\u043e\u0442\u044b \u043f\u0442\u0438\u0447\u044c\u0435\u0433\u043e \u043f\u043e\u043b\u0451\u0442\u0430\u041e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 scheme\u00a0http\/https\u00a0\u0434\u0430\u0451\u0442 \u0434\u0432\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0440\u043e\u043b\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0441\u0442\u043e\u0438\u0442 \u043e\u043d \u0432\u00a0From(&#8230;)\u00a0\u0438\u043b\u0438 \u0432\u00a0To(&#8230;):\u0420\u043e\u043b\u044c\u041a\u043b\u0430\u0441\u0441\u041d\u0430 \u0447\u0451\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u00a0(From)HttpConsumerKestrel\u041f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u00a0(To)HttpProducerHttpClient\u0428\u043b\u0451\u0442 \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0430\u0434\u0440\u0435\u0441\u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 DSL \u2014 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u044b\u00a0Http\u00a0\u0438\u00a0Https\u00a0(redb.Route.Http\/Fluent\/HttpDsl.cs):\/\/ \u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u2014 \u0441\u043b\u0443\u0448\u0430\u0435\u043c \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435.From(Http.Listen(&#171;\/webhook&#187;).Port(8080).Cors(&#171;https:\/\/app.example.com&#187;).InOut())\/\/ \u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 \u2014 \u0448\u043b\u0451\u043c \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435.To(Http.Post(&#171;api.example.com\/orders&#187;).BearerAuth().Timeout(5000))\u041b\u0438\u0431\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0439 URI \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e (\u0431\u0438\u043b\u0434\u0435\u0440 \u0440\u043e\u0432\u043d\u043e \u0432 \u043d\u0435\u0451 \u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f):.From(&#171;http:0.0.0.0:8080\/webhook?cors=true&amp;corsOrigins=https:\/\/app.example.com&amp;inOut=true&#187;).To(&#171;http:api.example.com\/orders?method=POST&amp;timeout=5000&#187;)\u041c\u0435\u0442\u043e\u0434\u044b HTTP: \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 \u0441\u043b\u0443\u0448\u0430\u0435\u0442, \u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 \u0448\u043b\u0451\u0442\u041c\u0435\u0442\u043e\u0434\u044b (GET\/POST\/PUT\/\u2026) \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u0440\u043e\u043b\u0435\u0439 \u2014 \u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e. \u0421\u043d\u0430\u0447\u0430\u043b\u0430\u00a0\u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u00a0(To) \u2014 \u043a\u0430\u043a\u043e\u0439 \u043c\u0435\u0442\u043e\u0434\u00a0\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c:\/\/ fluent \u2014 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0444\u0430\u0431\u0440\u0438\u0447\u043d\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c:.To(Http.Get(&#171;api.example.com\/users&#187;))           \/\/ GET.To(Http.Post(&#171;api.example.com\/users&#187;))          \/\/ POST.To(Http.Put(&#171;api.example.com\/users\/42&#187;))        \/\/ PUT.To(Http.Delete(&#171;api.example.com\/users\/42&#187;))     \/\/ DELETE.To(Http.Patch(&#171;api.example.com\/users\/42&#187;))      \/\/ PATCH.To(Http.Head(&#171;api.example.com\/users\/42&#187;))       \/\/ HEAD\/\/ \u0442\u043e \u0436\u0435 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 URI (\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u2014 method):.To(&#171;http:api.example.com\/users?method=POST&#187;)\/\/ \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 \u043b\u0435\u0442\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u043e\u043d \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442 \u0443 \u043e\u043f\u0446\u0438\u0438:.SetHeader(&#171;redbHttp.Method&#187;, &#171;PUT&#187;).To(Http.Post(&#171;api.example.com\/users\/42&#187;))        \/\/ \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u0439\u0434\u0451\u0442 PUT\u0422\u0435\u043f\u0435\u0440\u044c\u00a0\u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u00a0(From) \u2014 \u043a\u0430\u043a\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b\u00a0\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c:\/\/ \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0412\u0421\u0415 \u043c\u0435\u0442\u043e\u0434\u044b:.From(Http.Listen(&#171;\/webhook&#187;).Port(8080))\/\/ \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d\u043d\u044b\u0445 (\u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u2192 405 Method Not Allowed):.From(Http.Listen(&#171;\/webhook&#187;).Port(8080).Methods(&#171;POST&#187;)).From(Http.Listen(&#171;\/orders&#187;).Port(8080).Methods(&#171;POST,PUT&#187;))\/\/ \u0442\u043e \u0436\u0435 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 URI (\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u2014 methods):.From(&#171;http:0.0.0.0:8080\/webhook?methods=POST&#187;)\/\/ \u0448\u043e\u0440\u0442\u043a\u0430\u0442: \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0443\u0442\u0438 (\u0434\u043b\u044f \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u0430):.From(&#171;http:POST:0.0.0.0:8080\/webhook&#187;).From(&#171;http:GET:\/health&#187;)\u041a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u0445 \u043b\u0435\u0433\u043a\u043e \u043f\u0443\u0442\u0430\u0435\u0442\u0441\u044f:\u041f\u0440\u043e\u0434\u044e\u0441\u0435\u0440 (To)\u041a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440 (From)\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 URImethod\u00a0(\u0435\u0434. \u0447.)methods\u00a0(\u043c\u043d. \u0447., \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e)\u0421\u043c\u044b\u0441\u043b\u043a\u0430\u043a\u043e\u0439 \u043c\u0435\u0442\u043e\u0434\u00a0\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u043a\u0430\u043a\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b\u00a0\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c\u00a0(\u043f\u0443\u0441\u0442\u043e = \u0432\u0441\u0435)\u0414\u0435\u0444\u043e\u043b\u0442GET\u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044bOverride \u043d\u0430 \u043b\u0435\u0442\u0443\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a\u00a0redbHttp.Method\u2014 (\u0444\u0438\u043b\u044c\u0442\u0440 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u043d)\u041f\u0440\u0435\u0444\u0438\u043a\u0441-\u0448\u043e\u0440\u0442\u043a\u0430\u0442 (http:POST:\/&#8230;) \u2014 \u0447\u0430\u0441\u0442\u043d\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439: \u043e\u043d \u0441\u0442\u0430\u0432\u0438\u0442\u00a0\u043e\u0431\u0430\u00a0\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0440\u0430\u0437\u0443 (\u0438\u00a0method, \u0438\u00a0methods), \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u0434\u043d\u0430 \u0438 \u0442\u0430 \u0436\u0435 \u0437\u0430\u043f\u0438\u0441\u044c \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u043f\u0440\u043e\u0434\u044e\u0441\u0435\u0440\u043e\u043c, \u0438 \u043a\u043e\u043d\u0441\u044c\u044e\u043c\u0435\u0440\u043e\u043c.\u0418 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u0451\u043c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430 \u043e\u0434\u0438\u043d \u043f\u0443\u0442\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442\u00a0\u0440\u0430\u0437\u043d\u044b\u0435\u00a0\u043c\u0435\u0442\u043e\u0434\u044b: \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438 \u0440\u0430\u0437\u0432\u043e\u0434\u0438\u043c Content-Based Router&#8217;\u043e\u043c \u043f\u043e\u00a0redbHttp.Method\u00a0(\u044d\u0442\u043e \u0440\u043e\u0432\u043d\u043e \u043f\u0440\u043e\u0434-\u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u0447\u0430\u0441\u0442\u0438 1):.From(Http.Listen(&#171;\/api\/tsum\/user-filters&#187;).Port(5090).Methods(&#171;GET,POST&#187;).Cors(&#171;*&#187;).InOut())    .Choice()        .When(e =&gt; GetHeader(e, &#171;redbHttp.Method&#187;) == &#171;POST&#187;)            .ProcessWithRedb((redb, ex, ct) =&gt; HandlePost(redb, ex))   \/\/ \u0437\u0430\u043f\u0438\u0441\u044c        .Otherwise()            .ProcessWithRedb((redb, ex, ct) =&gt; HandleGet(redb, ex))    \/\/ \u0447\u0442\u0435\u043d\u0438\u0435    .EndChoice();\u0414\u0430\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0431\u0435 \u0440\u043e\u043b\u0438 \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u2014 \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441.\u0427\u0430\u0441\u0442\u044c 3. \u00ab\u0410 \u0433\u0434\u0435 \u0436\u0435 ASP.NET?\u00bb \u2014 \u0435\u0433\u043e \u043d\u0435\u0442, \u0438 \u044d\u0442\u043e \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u041a\u043e\u0433\u0434\u0430 .NET-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043b\u044b\u0448\u0438\u0442 \u00ab\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 HTTP-\u0441\u0435\u0440\u0432\u0435\u0440\u00bb, \u043e\u043d \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u00a0WebApplication, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b,\u00a0[HttpPost], \u0444\u0438\u043b\u044c\u0442\u0440\u044b, model binding,\u00a0app.UseRouting(),\u00a0app.UseCors(), DI-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440 middleware.\u00a0\u0412 HTTP-\u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0435 redb.Route \u043d\u0438\u0447\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0442.\u00a0\u0415\u0441\u0442\u044c Kestrel \u2014 \u0433\u043e\u043b\u044b\u0439, \u0431\u0435\u0437 MVC-\u043d\u0430\u0434\u0441\u0442\u0440\u043e\u0439\u043a\u0438.\u0412\u043e\u0442 \u043a\u0430\u043a \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440 (SharedHttpServerManager.StartServer, \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u043e):var builder = WebApplication.CreateSlimBuilder();   \/\/ slim&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-484156","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484156","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=484156"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484156\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=484156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=484156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=484156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}