Aracılığıyla paylaş


Azure API Management hizmetinden dış hizmetleri kullanma

UYGULANANLAR: Tüm API Management katmanları

Azure API Management hizmetinde sağlanan ilkeler yalnızca gelen istek, giden yanıt ve temel yapılandırma bilgilerine dayalı olarak çok çeşitli yararlı işler yapabilir. Ancak, API Management ilkelerinden dış hizmetlerle etkileşim kurabilmek birçok farklı fırsat sunar.

Önceki makalelerde günlüğe kaydetme, izleme ve analiz için Azure Event Hubs hizmetiyle nasıl etkileşim kurabileceğinizi gördünüz. Bu makalede, herhangi bir dış HTTP tabanlı hizmetle etkileşim kurmanıza olanak sağlayan ilkeler gösterilmektedir. Bu ilkeler, uzak olayları tetikleme veya özgün isteği ve yanıtı bir şekilde işlemek için kullanılan bilgileri almak için kullanılabilir.

Tek Yönlü İstek Gönder

Büyük olasılıkla en basit dış etkileşim, bir dış hizmete önemli bir olay hakkında bildirim gönderilmesini sağlayan isteğin tetikle ve unut stilidir. Denetim akışı ilkesi choose , ilgilendiğiniz her türlü koşulu algılamak için kullanılabilir. Koşul karşılanırsa, send-one-way-request ilkesini kullanarak bir dış HTTP isteği oluşturabilirsiniz. Bu istek Hipchat veya Slack gibi bir mesajlaşma sistemine ya da SendGrid veya MailChimp gibi bir posta API'sine ya da PagerDuty gibi kritik destek olayları için olabilir. Bu mesajlaşma sistemlerinin tümü çağrılabilen basit HTTP API'lerine sahiptir.

Slack ile uyarı oluşturma

Aşağıdaki örnekte, HTTP yanıt durumu kodu 500'den büyük veya buna eşitse Slack sohbet odasına ileti gönderme işlemi gösterilmektedir. 500 aralık hatası, arka uç API'siyle ilgili, API istemcisinin kendi kendine çözümleyememe sorununu gösterir. Genellikle API Management bölümünde bir tür müdahale gerektirir.

<choose>
  <when condition="@(context.Response.StatusCode >= 500)">
    <send-one-way-request mode="new">
      <set-url>https://hooks.slack.com/services/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</set-url>
      <set-method>POST</set-method>
      <set-body>@{
        return new JObject(
          new JProperty("username","APIM Alert"),
          new JProperty("icon_emoji", ":ghost:"),
          new JProperty("text", String.Format("{0} {1}\nHost: {2}\n{3} {4}\n User: {5}",
            context.Request.Method,
            context.Request.Url.Path + context.Request.Url.QueryString,
            context.Request.Url.Host,
            context.Response.StatusCode,
            context.Response.StatusReason,
            context.User.Email
          ))
        ).ToString();
      }</set-body>
    </send-one-way-request>
  </when>
</choose>

Slack, gelen web kancaları kavramına sahiptir. Slack, bir gelen web kancası yapılandırdığında, temel bir POST isteği yapmanıza ve Slack kanalına bir ileti iletmenize olanak tanıyan özel bir URL oluşturur. Oluşturduğunuz JSON gövdesi Slack tarafından tanımlanan bir biçimi temel alır.

Slack Web Kancası'nın gösterildiği ekran görüntüsü.

Ateş ve unutmak yeterli mi?

İstek gönderirken, "ateş et ve unut" tarzını kullanmanın belirli ödünleri vardır. Bir nedenden dolayı istek başarısız olursa, hata bildirilmez. Bu durumda, ikincil hata raporlama sisteminin karmaşıklığı ve yanıtı beklemenin ek performans yükü haklı değildir. Yanıtı denetlemenin gerekli olduğu senaryolarda , istek gönderme ilkesi daha iyi bir seçenektir.

İstek Gönder

İlke, send-request karmaşık işleme işlevleri gerçekleştirmek ve daha fazla ilke işleme için kullanılabilecek verileri API yönetim hizmetine döndürmek için bir dış hizmet kullanılmasını sağlar.

Başvuru belirteçlerini yetkilendirme

API Management'ın önemli bir işlevi arka uç kaynaklarını korumaktır. API'niz tarafından kullanılan yetkilendirme sunucusu, Microsoft Entra Id'nin yaptığı gibi OAuth2 akışının bir parçası olarak JSON Web Belirteçleri (JWT) oluşturuyorsa, belirtecin geçerliliğini doğrulamak için ilkeyi veya validate-jwt ilkeyi kullanabilirsinizvalidate-azure-ad-token. Bazı yetkilendirme sunucuları, yetkilendirme sunucusuna geri çağırma yapmadan doğrulanamayan başvuru belirteçleri olarak adlandırılan belirteçleri oluşturur.

Standartlaştırılmış iç gözlem

Geçmişte, bir yetkilendirme sunucusuyla başvuru belirtecini doğrulamanın standart bir yolu yoktu. Ancak, İnternet Mühendisliği Görev Gücü (IETF) kısa süre önce bir kaynak sunucusunun belirtecin geçerliliğini nasıl doğrulayabileceğinizi tanımlayan önerilen standart RFC 7662'yi yayımladı.

Belirteci ayıklamak

İlk adım, yetkilendirme başlığından belirteci ayıklamaktır. Başlık değeri, Bearer yetkilendirme şeması, tek bir boşluk ve ardından RFC 6750'ye göre yetkilendirme belirteci ile biçimlendirilmelidir. Ne yazık ki yetkilendirme düzeninin atlandığı durumlar vardır. Ayrıştırma sırasında bu eksikliği hesaba katmak için API Management, üst bilgi değerini bir alana böler ve döndürülen dize dizisinden son dizeyi seçer. Bu yöntem, hatalı biçimlendirilmiş yetkilendirme üst bilgileri için geçici bir çözüm sağlar.

<set-variable name="token" value="@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param").Split(' ').Last())" />

Doğrulama isteğinde bulunma

API Management yetkilendirme belirtecine sahip olduktan sonra API Management, belirteci doğrulama isteğinde bulunabilir. RFC 7662 bu işlem iç gözlemini çağırır ve iç gözlem kaynağına bir HTML formu göndermenizi POST gerektirir. HTML formu en azından anahtarı token olan bir anahtar/değer çifti içermelidir. Kötü amaçlı istemcilerin geçerli belirteçleri arayamayacağından emin olmak için yetkilendirme sunucusuna yapılan bu isteğin de kimliği doğrulanmalıdır.

<send-request mode="new" response-variable-name="tokenstate" timeout="20" ignore-error="true">
  <set-url>https://microsoft-apiappec990ad4c76641c6aea22f566efc5a4e.azurewebsites.net/introspection</set-url>
  <set-method>POST</set-method>
  <set-header name="Authorization" exists-action="override">
    <value>basic dXNlcm5hbWU6cGFzc3dvcmQ=</value>
  </set-header>
  <set-header name="Content-Type" exists-action="override">
    <value>application/x-www-form-urlencoded</value>
  </set-header>
  <set-body>@($"token={(string)context.Variables["token"]}")</set-body>
</send-request>

Yanıtı kontrol etme

response-variable-name özniteliği, döndürülen yanıta erişim vermek için kullanılır. Bu özellikte tanımlanan ad, context.Variables sözlüğünde IResponse nesnesine erişmek için bir anahtar olarak kullanılabilir.

Yanıt nesnesinden gövdeyi alabilirsiniz ve RFC 7622 API Management'a yanıtın bir JSON nesnesi olması gerektiğini ve boole değeri olarak adlandırılan active en az bir özellik içermesi gerektiğini söyler. True active olduğunda belirteç geçerli kabul edilir.

Alternatif olarak, yetkilendirme sunucusu belirtecin geçerli olup olmadığını belirten alanı içermiyorsa "active" , geçerli bir belirteçte hangi özelliklerin ayarlandığını belirlemek için gibi curl bir HTTP istemci aracı kullanın. Örneğin, geçerli bir belirteç yanıtı adlı "expires_in"bir özellik içeriyorsa, bu özellik adının yetkilendirme sunucusu yanıtında şu şekilde olup olmadığını denetleyin:

<when condition="@(((IResponse)context.Variables["tokenstate"]).Body.As<JObject>().Property("expires_in") == null)">

Raporlama hatası

Belirtecin geçersiz olup olmadığını algılamak ve varsa 401 yanıtı döndürmek için bir ilke kullanabilirsiniz <choose> .

<choose>
  <when condition="@((bool)((IResponse)context.Variables["tokenstate"]).Body.As<JObject>()["active"] == false)">
    <return-response response-variable-name="existing response variable">
      <set-status code="401" reason="Unauthorized" />
      <set-header name="WWW-Authenticate" exists-action="override">
        <value>Bearer error="invalid_token"</value>
      </set-header>
    </return-response>
  </when>
</choose>

Belirteçlerin nasıl kullanılması gerektiğini açıklayan bearer göre API Management, 401 yanıtını içeren bir WWW-Authenticate üst bilgi de döndürür. WWW-Authenticate, bir istemciye doğru yetkilendirilmiş istek oluşturma hakkında bilgi vermek için tasarlanmıştır. OAuth2 çerçevesiyle mümkün olan çok çeşitli yaklaşımlar nedeniyle, gerekli tüm bilgileri iletmek zordur. Neyse ki istemcilerin bir kaynak sunucusuna yönelik istekleri düzgün bir şekilde yetkilendirmesini keşfetmesine yardımcı olmak için çalışmalar devam ediyor.

Son çözüm

Sonunda aşağıdaki ilkeyi alırsınız:

<inbound>
  <!-- Extract Token from Authorization header parameter -->
  <set-variable name="token" value="@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param").Split(' ').Last())" />

  <!-- Send request to Token Server to validate token (see RFC 7662) -->
  <send-request mode="new" response-variable-name="tokenstate" timeout="20" ignore-error="true">
    <set-url>https://microsoft-apiappec990ad4c76641c6aea22f566efc5a4e.azurewebsites.net/introspection</set-url>
    <set-method>POST</set-method>
    <set-header name="Authorization" exists-action="override">
      <value>basic dXNlcm5hbWU6cGFzc3dvcmQ=</value>
    </set-header>
    <set-header name="Content-Type" exists-action="override">
      <value>application/x-www-form-urlencoded</value>
    </set-header>
    <set-body>@($"token={(string)context.Variables["token"]}")</set-body>
  </send-request>

  <choose>
    <!-- Check active property in response -->
    <when condition="@((bool)((IResponse)context.Variables["tokenstate"]).Body.As<JObject>()["active"] == false)">
      <!-- Return 401 Unauthorized with http-problem payload -->
      <return-response response-variable-name="existing response variable">
        <set-status code="401" reason="Unauthorized" />
        <set-header name="WWW-Authenticate" exists-action="override">
          <value>Bearer error="invalid_token"</value>
        </set-header>
      </return-response>
    </when>
  </choose>
  <base />
</inbound>

Bu örnek, ilkenin send-request yararlı dış hizmetleri API Management hizmeti aracılığıyla akan istekler ve yanıtlar süreciyle tümleştirmek için nasıl kullanılabileceğini gösteren birçok örnekten yalnızca biridir.

Yanıt Oluşturma

İlke send-request , önceki örnekte gördüğünüz gibi bir arka uç sistemine yönelik birincil isteği geliştirmek için veya arka uç çağrısını tamamen değiştirmek için kullanılabilir. Bu tekniği kullanarak, birden çok farklı sistemden toplanan bileşik kaynakları kolayca oluşturabilirsiniz.

Pano oluşturma

Bazen birden çok arka uç sisteminde bulunan bilgileri (örneğin, bir panoyu yönlendirmek için) kullanıma sunmanız gerekir. Ana performans göstergeleri (KPI' ler) tüm farklı arka uçlardan gelir, ancak bunlara doğrudan erişim sağlamayı tercih etmek istemezsiniz. Yine de, tüm bilgilerin tek bir istekte alınması iyi olur. Belki de arka plan bilgilerinin önce biraz işlenip düzenlenmeye ve temizlenmeye ihtiyacı vardır! Bu bileşik kaynağı önbelleğe almak, kullanıcıların düşük performans gösteren ölçümlerinin değişip değişmeyeceğini görmek için F5 tuşuna basma alışkanlığına sahip olduğunu bildiğiniz için sunucu yükünü azaltmanın yararlı bir yolu olabilir.

Kaynağı sahtecilik yapmak

Pano kaynağını oluşturmanın ilk adımı, Azure portalında yeni bir işlem yapılandırmaktır. Bu yer tutucu işlemi, dinamik kaynağı oluşturmak için bir bileşim politikasını yapılandırmak üzere kullanılır.

Azure portalında yapılandırılan yeni Pano işlemini gösteren ekran görüntüsü.

İstekleri yapma

İşlem oluşturulduktan sonra, özellikle bu işlem için bir ilke yapılandırabilirsiniz.

Politika kapsamını gösteren bir ekran görüntüsü.

İlk adım, gelen istekten tüm sorgu parametrelerini ayıklamaktır, böylece bunları arka uçtan iletebilirsiniz. Bu örnekte pano, belirli bir süreye göre bilgileri gösterir ve bu nedenle ve fromDatetoDate parametresine sahiptir. İstek URL'sinden set-variable bilgileri ayıklamak için ilkeyi kullanabilirsiniz.

<set-variable name="fromDate" value="@(context.Request.Url.Query["fromDate"].Last())">
<set-variable name="toDate" value="@(context.Request.Url.Query["toDate"].Last())">

Bu bilgilere sahip olduktan sonra tüm arka uç sistemlerine istekte bulunabilirsiniz. Her istek, parametre bilgileriyle yeni bir URL oluşturur ve ilgili sunucusunu çağırır ve yanıtı bir bağlam değişkeninde depolar.

<send-request mode="new" response-variable-name="revenuedata" timeout="20" ignore-error="true">
  <set-url>@($"https://accounting.acme.com/salesdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
  <set-method>GET</set-method>
</send-request>

<send-request mode="new" response-variable-name="materialdata" timeout="20" ignore-error="true">
  <set-url>@($"https://inventory.acme.com/materiallevels?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
  <set-method>GET</set-method>
</send-request>

<send-request mode="new" response-variable-name="throughputdata" timeout="20" ignore-error="true">
  <set-url>@($"https://production.acme.com/throughput?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
  <set-method>GET</set-method>
</send-request>

<send-request mode="new" response-variable-name="accidentdata" timeout="20" ignore-error="true">
  <set-url>@($"https://production.acme.com/accidentdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
  <set-method>GET</set-method>
</send-request>

API Management bu istekleri sırayla gönderir.

Yanıt

Bileşik yanıtı oluşturmak için return-response ilkesini kullanabilirsiniz. set-body öğesi, özellik olarak eklenmiş tüm bileşen gösterimleriyle yeni bir JObject oluşturmak için bir ifade kullanabilir.

<return-response response-variable-name="existing response variable">
  <set-status code="200" reason="OK" />
  <set-header name="Content-Type" exists-action="override">
    <value>application/json</value>
  </set-header>
  <set-body>
    @(new JObject(new JProperty("revenuedata",((IResponse)context.Variables["revenuedata"]).Body.As<JObject>()),
                  new JProperty("materialdata",((IResponse)context.Variables["materialdata"]).Body.As<JObject>()),
                  new JProperty("throughputdata",((IResponse)context.Variables["throughputdata"]).Body.As<JObject>()),
                  new JProperty("accidentdata",((IResponse)context.Variables["accidentdata"]).Body.As<JObject>())
                  ).ToString())
  </set-body>
</return-response>

İlkenin tamamı aşağıdaki gibi görünür:

<policies>
  <inbound>
    <set-variable name="fromDate" value="@(context.Request.Url.Query["fromDate"].Last())">
    <set-variable name="toDate" value="@(context.Request.Url.Query["toDate"].Last())">

    <send-request mode="new" response-variable-name="revenuedata" timeout="20" ignore-error="true">
      <set-url>@($"https://accounting.acme.com/salesdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
      <set-method>GET</set-method>
    </send-request>

    <send-request mode="new" response-variable-name="materialdata" timeout="20" ignore-error="true">
      <set-url>@($"https://inventory.acme.com/materiallevels?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
      <set-method>GET</set-method>
    </send-request>

    <send-request mode="new" response-variable-name="throughputdata" timeout="20" ignore-error="true">
      <set-url>@($"https://production.acme.com/throughput?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
      <set-method>GET</set-method>
    </send-request>

    <send-request mode="new" response-variable-name="accidentdata" timeout="20" ignore-error="true">
      <set-url>@($"https://production.acme.com/accidentdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
      <set-method>GET</set-method>
    </send-request>

    <return-response response-variable-name="existing response variable">
      <set-status code="200" reason="OK" />
      <set-header name="Content-Type" exists-action="override">
        <value>application/json</value>
      </set-header>
      <set-body>
        @(new JObject(new JProperty("revenuedata",((IResponse)context.Variables["revenuedata"]).Body.As<JObject>()),
                      new JProperty("materialdata",((IResponse)context.Variables["materialdata"]).Body.As<JObject>()),
                      new JProperty("throughputdata",((IResponse)context.Variables["throughputdata"]).Body.As<JObject>()),
                      new JProperty("accidentdata",((IResponse)context.Variables["accidentdata"]).Body.As<JObject>())
        ).ToString())
      </set-body>
    </return-response>
  </inbound>
  <backend>
    <base />
  </backend>
  <outbound>
    <base />
  </outbound>
</policies>

Özet

Azure API Management hizmeti, HTTP trafiğine seçmeli olarak uygulanabilen esnek ilkeler sağlar ve arka uç hizmetlerinin bileşimini sağlar. API ağ geçidinizi uyarı işlevleri, doğrulama, geçerlilik kontrolü özellikleriyle geliştirmek veya birden çok arka uç hizmetine dayalı yeni bileşik kaynaklar oluşturmak istediğinizde, send-request ve ilgili ilkeler bir dünya dolusu olasılığı açar.