Web API'si uygulaması

Dikkatlice tasarlanmış bir RESTful web API'si, istemci uygulamaları tarafından erişilebilen kaynakları, ilişkileri ve gezinti düzenlerini tanımlar. Bir web API’sini uygulayıp dağıttığınızda, verilerin mantıksal yapısı yerine web API’sini barındıran ortamın fiziksel gereksinimlerini ve web API'sinin hangi şekilde oluşturulduğunu göz önünde bulundurmanız gerekir. Bu kılavuz, bir web API'sini uygulamaya ve istemci uygulamalarının kullanımına açmak için yayımlamaya yönelik en iyi yöntemlere odaklanır. Web API'si tasarımı hakkında ayrıntılı bilgi için bkz . Web API'si tasarımı.

İstekleri işleme

İstekleri işlemek üzere kod uygularken aşağıdaki noktaları göz önünde bulundurun.

GET, PUT, DELETE, HEAD ve PATCH eylemleri bir kez etkili olmalıdır

Bu istekleri uygulayan kod herhangi yan etki oluşturmamalıdır. Aynı kaynak üzerinde yinelenen aynı istek, aynı durumla sonuçlanmalıdır. Örneğin, yanıt iletilerindeki HTTP durum kodu farklı olsa da, aynı URI'ye birden çok DELETE isteği göndermek aynı etkiye sahip olmalıdır. İlk DELETE isteği 204 (İçerik Yok) durum kodunu, sonraki bir DELETE isteği ise 404 (Bulunamadı) durum kodunu döndürebilir.

Not

Jonathan Oliver'ın blogundaki Idempotency Patterns (Tek Etkililik Desenleri) makalesi, tek etkililiğe ve bunun veri yönetimi işlemleriyle ilişkisine genel bir bakış sağlar.

Yeni kaynaklar oluşturan POST eylemlerinin ilişkisiz yan etkileri olmamalıdır

POST isteğinin yeni bir kaynak oluşturması amaçlanıyorsa, isteğin etkileri yeni kaynakla (ve bir tür bağlantı söz konusuysa muhtemelen doğrudan ilgili tüm kaynaklarda) sınırlandırılmalıdır. Örneğin, bir e-ticaret sisteminde, müşteri için yeni bir sipariş oluşturan bir POST isteği de envanter düzeylerini değiştirebilir ve fatura bilgileri oluşturabilir, ancak siparişle doğrudan ilgili olmayan bilgileri değiştirmemeli veya sistemin genel durumu üzerinde başka bir yan etkisi olmamalıdır.

Sık iletişim kuran POST, PUT ve DELETE işlemlerini uygulamaktan kaçının

Kaynak koleksiyonları üzerinden POST, PUT ve DELETE isteklerini destekleyin. Bir POST isteği birden çok yeni kaynağın ayrıntılarını içerebilir ve tümünü aynı koleksiyona ekleyebilir; bir PUT isteği bir koleksiyondaki tüm kaynak kümesini değiştirebilir; bir DELETE isteği ise bir koleksiyonun tamamını kaldırabilir.

ASP.NET Web API 2’ye dahil edilen OData desteği, istekleri toplu olarak yapma olanağı sağlar. Bir istemci uygulaması birkaç web API isteğini paketleyip tek bir HTTP isteği halinde sunucuya gönderebilir ve her bir isteğe yönelik yanıtları içeren tek bir HTTP yanıtı alabilir. Daha fazla bilgi için bkz . Web API'sinde ve Web API'sinde OData toplu iş desteğine giriş.

Yanıt gönderirken HTTP belirtimini takip edin

Bir web API’si, istemcinin sonucu nasıl işleyeceğini belirlemesi için doğru HTTP durum kodunu, istemcinin sonucun niteliğini anlayabilmesi için uygun HTTP üst bilgilerini ve istemcinin sonucu ayrıştırması için uygun şekilde biçimlendirilmiş bir gövdeyi içeren iletiler döndürmelidir.

Örneğin, bir POST işlemi 201 (Oluşturuldu) durum kodunu döndürmeli ve yanıt iletisi, yanıt iletisinin Konum üst bilgisinde yeni oluşturulan kaynağa ait URI’yi içermelidir.

İçerik anlaşmasını destekler

Bir yanıt iletisinin gövdesi, çeşitli biçimlerde veriler içerebilir. Örneğin, bir HTTP GET isteği JSON veya XML biçiminde veri döndürebilir. İstemciler bir istek gönderdiğinde, işleyebileceği veri biçimlerini belirten bir Accept üst bilgisi içerebilir. Bu biçimler medya türleri olarak belirtilir. Örneğin, bir görüntüyü alan bir GET isteği veren bir istemci, istemcinin işleyebileceği medya türlerini listeleyen accept üst bilgisini (gibi) image/jpeg, image/gif, image/pngbelirtebilir. Web API'si sonucu döndürdüğünde bu medya türlerinden birini kullanarak verileri biçimlendirmeli ve biçimi yanıtın Content-Type üst bilgisinde belirtmelidir.

İstemci bir Accept üst bilgisi belirtmezse, yanıt gövdesi için duyarlı bir varsayılan biçim kullanın. Örnek olarak ASP.NET Web API çerçevesi, metin tabanlı veriler için varsayılan olarak JSON biçimindedir.

HATEOAS yaklaşımı, istemcinin bir başlangıç noktasından itibaren gezinip kaynakları bulmasını sağlar. Bu işlem, URI'ler içeren bağlantılar kullanılarak yapılır; istemci bir kaynağı almak için HTTP GET isteği gönderdiğinde, yanıt bir istemci uygulamanın dolaylı olarak ilgili tüm kaynakları hızlıca bulmasını sağlayan URI’ler içermelidir. Örneğin, e-ticaret çözümünü destekleyen bir web API’de müşteri çok sayıda sipariş vermiş olabilir. Bir istemci uygulama bir müşterinin ayrıntılarını aldığında yanıt, istemci uygulamanın bu siparişleri alabilmesi için HTTP GET istekleri göndermesini sağlayan bağlantılar içermelidir. Ayrıca, HATEOAS stili bağlantılar her bağlantılı kaynağın her bir isteği gerçekleştirmek üzere karşılık gelen URI ile birlikte desteklediği diğer işlemleri (POST, PUT, DELETE vb.) açıklamalıdır. Bu yaklaşım API tasarımında daha ayrıntılı olarak açıklanmıştır.

Şu anda HATEOAS uygulamasını yöneten bir standart bulunmamasına karşın aşağıdaki örnekte olası bir yaklaşım gösterilmektedir. Bu örnekte, müşterinin ayrıntılarını bulan bir HTTP GET isteği, söz konusu müşterinin siparişlerine başvuran HATEOAS bağlantılarını içeren bir yanıt döndürür:

GET https://adventure-works.com/customers/2 HTTP/1.1
Accept: text/json
...
HTTP/1.1 200 OK
...
Content-Type: application/json; charset=utf-8
...
Content-Length: ...
{"CustomerID":2,"CustomerName":"Bert","Links":[
    {"rel":"self",
    "href":"https://adventure-works.com/customers/2",
    "action":"GET",
    "types":["text/xml","application/json"]},
    {"rel":"self",
    "href":"https://adventure-works.com/customers/2",
    "action":"PUT",
    "types":["application/x-www-form-urlencoded"]},
    {"rel":"self",
    "href":"https://adventure-works.com/customers/2",
    "action":"DELETE",
    "types":[]},
    {"rel":"orders",
    "href":"https://adventure-works.com/customers/2/orders",
    "action":"GET",
    "types":["text/xml","application/json"]},
    {"rel":"orders",
    "href":"https://adventure-works.com/customers/2/orders",
    "action":"POST",
    "types":["application/x-www-form-urlencoded"]}
]}

Bu örnekte müşteri verilerini, aşağıdaki kod parçacığında gösterilen Customer sınıfı temsil eder. HATEOAS bağlantıları Links koleksiyon özelliğinde tutulur:

public class Customer
{
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
    public List<Link> Links { get; set; }
    ...
}

public class Link
{
    public string Rel { get; set; }
    public string Href { get; set; }
    public string Action { get; set; }
    public string [] Types { get; set; }
}

HTTP GET işlemi, depolama alanından müşteri verilerini alıp bir Customer nesnesi oluşturur ve sonra Links koleksiyonunu doldurur. Sonuç bir JSON yanıt iletisi olarak biçimlendirilir. Her bağlantı aşağıdaki alanları içerir:

  • Döndürülen nesne ile bağlantı tarafından açıklanan nesne arasındaki ilişki (Rel). Bu durumda self , bağlantının nesnenin kendisine bir başvuru olduğunu (nesne odaklı birçok dildeki işaretçiye this benzer) ve orders ilgili sipariş bilgilerini içeren bir koleksiyonun adı olduğunu gösterir.
  • Bağlantı tarafından tanımlanan nesnenin URI biçimindeki köprü bağlantısı (Href).
  • Bu URI’ya gönderilebilen HTTP isteğinin türü (Action).
  • İstek türüne bağlı olarak, HTTP isteğinde belirtilmesi gereken veya yanıtta döndürülebilecek her türlü verinin biçimi (Types).

Örnek HTTP yanıtında gösterilen HATEOAS bağlantıları, bir istemci uygulamanın aşağıdaki işlemleri gerçekleştirebileceğini ifade eder:

  • Müşterinin ayrıntılarını getirmek için (tekrar) https://adventure-works.com/customers/2 URI’ya gönderilen HTTP GET isteği. Veriler, XML veya JSON olarak döndürülebilir.
  • Müşterinin ayrıntılarını değiştirmek için https://adventure-works.com/customers/2 URI’ya gönderilen HTTP PUT isteği. Yeni veriler, yanıt iletisinde x-www-form-urlencoded biçiminde belirtilmelidir.
  • Müşteri silmek için https://adventure-works.com/customers/2 URI’ya gönderilen HTTP DELETE isteği. İstek başka bir ek bilgi beklemez veya yanıt iletisi gövdesinde veri döndürmez.
  • Müşteriye ait tüm siparişleri bulmak için https://adventure-works.com/customers/2/orders URI’ya gönderilen HTTP GET isteği. Veriler, XML veya JSON olarak döndürülebilir.
  • Bu müşteri için yeni bir sipariş oluşturmak için URI'ye https://adventure-works.com/customers/2/orders bir HTTP POST isteği. Veriler, yanıt iletisinde x-www-form-urlencoded biçiminde belirtilmelidir.

Özel durum işleme

Bir işlem yakalanmayan bir özel durum oluşturursa aşağıdaki noktaları göz önünde bulundurun.

Özel durumları yakalama ve istemcilere anlamlı bir yanıt döndürme

Bir HTTP işlemi uygulayan kod, yakalanmayan özel durumların çerçeveye yayılmasına izin vermek yerine kapsamlı özel durum işleme sağlamalıdır. Bir özel durum nedeniyle işlemi tamamlamak mümkün değilse, özel durum yanıt iletisine geri gönderilebilir ancak özel durum nedeninin anlamlı bir açıklamasını içermelidir. Ayrıca özel durum, her durum için yalnızca 500 durum kodunu döndürmek yerine uygun HTTP durum kodunu da içermelidir. Örneğin, bir kullanıcı isteği sonucunda kısıtlamayı ihlal eden bir veritabanı güncelleştirmesi yapılırsa (bekleyen siparişleri olan bir müşteriyi silmeye çalışmak gibi), 409 (Çakışma) durum kodunu ve çakışma nedenini belirten bir ileti gövdesini döndürmeniz gerekir. Başka bir koşul isteği gerçekleştirilemez hale getirirse, 400 (Hatalı İstek) durum kodunu döndürebilirsiniz. HTTP durum kodlarının tam listesini W3C web sitesindeki Durum kodu tanımları sayfasında bulabilirsiniz.

Kod örneği farklı koşulları yakalar ve uygun bir yanıt döndürür.

[HttpDelete]
[Route("customers/{id:int}")]
public IHttpActionResult DeleteCustomer(int id)
{
    try
    {
        // Find the customer to be deleted in the repository
        var customerToDelete = repository.GetCustomer(id);

        // If there is no such customer, return an error response
        // with status code 404 (Not Found)
        if (customerToDelete == null)
        {
            return NotFound();
        }

        // Remove the customer from the repository
        // The DeleteCustomer method returns true if the customer
        // was successfully deleted
        if (repository.DeleteCustomer(id))
        {
            // Return a response message with status code 204 (No Content)
            // To indicate that the operation was successful
            return StatusCode(HttpStatusCode.NoContent);
        }
        else
        {
            // Otherwise return a 400 (Bad Request) error response
            return BadRequest(Strings.CustomerNotDeleted);
        }
    }
    catch
    {
        // If an uncaught exception occurs, return an error response
        // with status code 500 (Internal Server Error)
        return InternalServerError();
    }
}

İpucu

API'nize sızmaya çalışan bir saldırgan için yararlı olabilecek bilgiler eklemeyin.

Birçok web sunucusu, web API’sine ulaşmadan önce hata koşullarını kendi başına yakalar. Örneğin, bir web sitesi için kimlik doğrulamasını yapılandırırsanız ve kullanıcı doğru kimlik doğrulama bilgilerini sağlayamazsa, web sunucusunun 401 (Yetkisiz) durum koduyla yanıt vermesi gerekir. Bir istemcinin kimliği doğrulandıktan sonra kodunuz, istemcinin istenen kaynağa erişebildiğini doğrulamak üzere kendi denetimlerini gerçekleştirebilir. Bu yetkilendirme başarısız olursa, 403 (Yasak) durum kodunu döndürmeniz gerekir.

Özel durumları tutarlı bir şekilde işleme ve hata bilgilerini günlüğe kaydetme

Özel durumları tutarlı bir şekilde işlemek için web API'sinin tamamında genel bir hata işleme stratejisi uygulayın. Ayrıca, her bir özel durumun tam ayrıntılarını yakalayan hata günlüğünü eklemeniz gerekir; bu hata günlüğü, web üzerinden istemcilerin erişimine açılmadığı sürece ayrıntılı bilgiler içerebilir.

İstemci tarafı hataları ile sunucu tarafı hatalarını birbirinden ayırt etme

HTTP protokolü, istemci uygulamadan kaynaklanan hataları (HTTP 4xx durum kodları) sunucu üzerindeki bir sorundan kaynaklanan hatalardan (HTTP 5xx durum kodları) ayırt eder. Tüm hata yanıt iletilerinde bu kurala uyduğunuzdan emin olun.

İstemci tarafı veri erişimini en iyi duruma getirme

Web sunucusu ile istemci uygulamalar içerenler gibi dağıtılmış bir ortamda en önemli kaynaklardan birisi ağdır. Özellikle bir istemci uygulama sıklıkla istek gönderiyor veya veri alıyorsa bu durum önemli bir performans sorunu oluşturabilir. Bu nedenle, ağ üzerinden akan trafiği en aza indirmeyi amaçlamanız gerekir. Veri alıp sürdürmek üzere kod uygularken aşağıdaki noktaları göz önünde bulundurun:

İstemci tarafı önbelleğe alma desteği

HTTP 1.1 protokolü, istemcilerde ve Cache-Control üst bilgisi kullanılarak bir isteğin yönlendirildiği ara sunucularda önbelleğe almayı destekler. Bir istemci uygulama tarafından web API’sine HTTP GET isteği gönderildiğinde yanıt, yanıt gövdesindeki verilerin istemci tarafından veya isteğin yönlendirildiği bir ara sunucu tarafından güvenli bir şekilde önbelleğe alınıp alınamayacağını ve süresi dolmadan ve eski kabul edilmeden önce ne kadar süre kaldığını gösteren bir Cache-Control üst bilgisi içerebilir.

Aşağıdaki örnekte bir HTTP GET isteği ve Cache-Control üst bilgisi içeren ilgili yanıt gösterilmektedir:

GET https://adventure-works.com/orders/2 HTTP/1.1
HTTP/1.1 200 OK
...
Cache-Control: max-age=600, private
Content-Type: text/json; charset=utf-8
Content-Length: ...
{"orderID":2,"productID":4,"quantity":2,"orderValue":10.00}

Bu örnekte Cache-Control üst bilgisi, döndürülen verilerin süresinin 600 saniye sonra dolması gerektiğini ve yalnızca tek bir istemci için uygun olup diğer istemciler tarafından kullanılan ortak bir önbellekte depolanmaması gerektiğini (private olduğunu) belirtir. Cache-Control üst bilgisinin private yerine public seçeneğini belirttiğinde veriler ortak bir önbellekte depolanabilir veya no-store seçeneğini belirttiğinde verilerin istemci tarafından önbelleğe alınmaması gerekir. Aşağıdaki kod örneğinde, bir yanıt iletisinde Cache-Control üst bilgisinin nasıl oluşturulacağı gösterilmektedir:

public class OrdersController : ApiController
{
    ...
    [Route("api/orders/{id:int:min(0)}")]
    [HttpGet]
    public IHttpActionResult FindOrderByID(int id)
    {
        // Find the matching order
        Order order = ...;
        ...
        // Create a Cache-Control header for the response
        var cacheControlHeader = new CacheControlHeaderValue();
        cacheControlHeader.Private = true;
        cacheControlHeader.MaxAge = new TimeSpan(0, 10, 0);
        ...

        // Return a response message containing the order and the cache control header
        OkResultWithCaching<Order> response = new OkResultWithCaching<Order>(order, this)
        {
            CacheControlHeader = cacheControlHeader
        };
        return response;
    }
    ...
}

Bu kod adlı OkResultWithCachingözel IHttpActionResult bir sınıf kullanır. Bu sınıf, denetleyicinin önbellek üst bilgisi içeriklerini ayarlamasını sağlar:

public class OkResultWithCaching<T> : OkNegotiatedContentResult<T>
{
    public OkResultWithCaching(T content, ApiController controller)
        : base(content, controller) { }

    public OkResultWithCaching(T content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
        : base(content, contentNegotiator, request, formatters) { }

    public CacheControlHeaderValue CacheControlHeader { get; set; }
    public EntityTagHeaderValue ETag { get; set; }

    public override async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response;
        try
        {
            response = await base.ExecuteAsync(cancellationToken);
            response.Headers.CacheControl = this.CacheControlHeader;
            response.Headers.ETag = ETag;
        }
        catch (OperationCanceledException)
        {
            response = new HttpResponseMessage(HttpStatusCode.Conflict) {ReasonPhrase = "Operation was cancelled"};
        }
        return response;
    }
}

Not

HTTP protokolü ayrıca Cache-Control üst bilgisi için no-cache yönergesini tanımlar. Kafa karıştırıcı bir şekilde, bu yönerge "önbelleğe almama" yerine "önbelleğe alınan bilgileri döndürmeden önce sunucu ile yeniden doğrulama" anlamına gelir; veriler yine de önbelleğe alınabilir ancak her kullanıldığında hala güncel olup olmadığı denetlenir.

Önbellek yönetimi, istemci uygulamasının veya ara sunucunun sorumluluğundadır; ancak doğru şekilde uygulanırsa, yakın zamanda zaten alınmış verileri getirme gereksinimini ortadan kaldırarak bant genişliği kazandırabilir ve performansı artırabilir.

Cache-Control üst bilgisindeki max-age değeri yalnızca kılavuz niteliğindedir ve belirtilen süre boyunca ilgili verilerin değişmeyeceğini garanti etmez. Web API’si, verilerin beklenen geçiciliğine bağlı olarak max-age parametresini uygun bir değere ayarlamalıdır. Bu süre sona erdiğinde istemci, nesneyi önbellekten atmalıdır.

Not

Birçok modern web tarayıcısı, isteklere uygun cache-control üst bilgilerini ekleyerek ve sonuçların üst bilgilerini anlatılan şekilde inceleyerek istemci tarafı önbelleğe alma özelliğini destekler. Ancak, bazı eski tarayıcılar sorgu dizesi içeren bir URL’den döndürülen değerleri önbelleğe almaz. Bu sorun genellikle burada tartışılan protokolü temel alarak kendi önbellek yönetim stratejisini uygulayan özel istemci uygulamaları için geçerli değildir.

Bazı eski proxy'ler aynı davranışı sergiler ve sorgu dizeleriyle URL’lere göre istekleri önbelleğe almayabilir. Bu sorun, bu tür bir proxy üzerinden bir web sunucusuna bağlanan özel istemci uygulamaları için geçerli olabilir.

Sorgu işlemeyi iyileştirmek için Etag'ler sağlama

Bir istemci uygulama bir nesne aldığında, yanıt iletisi aynı zamanda bir ETag (Varlık Etiketi) içermelidir. ETag, kaynağın sürümünü gösteren opak bir dizedir; Bir kaynak her değiştiğinde ETag de değiştirilir. Bu ETag, istemci uygulama tarafından verilerin bir parçası olarak önbelleğe alınmalıdır. Aşağıdaki kod örneğinde bir HTTP GET isteğine yanıtın parçası olarak ETag ekleme işlemi gösterilmektedir. Bu kod, nesneyi tanımlayan sayısal bir değer oluşturmak üzere bir nesnenin GetHashCode yöntemini kullanır (gerekirse bu yöntemi geçersiz kılabilir ve MD5 gibi bir algoritma kullanarak kendi karmanızı oluşturabilirsiniz):

public class OrdersController : ApiController
{
    ...
    public IHttpActionResult FindOrderByID(int id)
    {
        // Find the matching order
        Order order = ...;
        ...

        var hashedOrder = order.GetHashCode();
        string hashedOrderEtag = $"\"{hashedOrder}\"";
        var eTag = new EntityTagHeaderValue(hashedOrderEtag);

        // Return a response message containing the order and the cache control header
        OkResultWithCaching<Order> response = new OkResultWithCaching<Order>(order, this)
        {
            ...,
            ETag = eTag
        };
        return response;
    }
    ...
}

Web API’si tarafından gönderilen yanıt iletisi şuna benzer:

HTTP/1.1 200 OK
...
Cache-Control: max-age=600, private
Content-Type: text/json; charset=utf-8
ETag: "2147483648"
Content-Length: ...
{"orderID":2,"productID":4,"quantity":2,"orderValue":10.00}

İpucu

Güvenlik nedeniyle, kimliği doğrulanmış (HTTPS) bağlantı üzerinden döndürülen hassas verilerin veya verilerin önbelleğe alınmasına izin verme.

Bir istemci uygulama herhangi bir zamanda aynı kaynağı almak için sonraki bir GET isteği düzenleyebilir ve kaynak değiştiyse (farklı ETag’e sahipse), önbelleğe alınan sürüm atılmalı ve yeni sürüm önbelleğe eklenmelidir. Bir kaynak büyükse ve istemciye geri iletmek için önemli miktarda bant genişliği gerektiriyorsa, aynı verileri getirmek için tekrarlanan istekleri verimsiz olabilir. Bu sorunla başa çıkmak için HTTP protokolü bir web API’sinde desteklemeniz gereken GET isteklerini iyileştirmeye yönelik aşağıdaki işlemi tanımlar:

  • İstemci, bir If-None-Match HTTP üst bilgisinde başvurulan kaynağın o anda önbelleğe alınan sürümü için ETag içeren bir GET isteği oluşturur:

    GET https://adventure-works.com/orders/2 HTTP/1.1
    If-None-Match: "2147483648"
    
  • Web API’sindeki GET işlemi, istenen veriler için geçerli ETag’i alır (yukarıdaki örnekte sipariş 2) ve If-None-Match üst bilgisindeki değerle karşılaştırır.

  • İstenen veriler için geçerli ETag, istek tarafından sağlanan ETag ile eşleşiyorsa kaynak değişmemiştir ve web API’si boş bir ileti ve 304 (Değiştirilmedi) durum kodu ile bir HTTP yanıtı döndürmelidir.

  • İstenen veriler için geçerli ETag, istek tarafından sağlanan ETag ile eşleşmiyorsa veriler değişmiştir ve web API’si, ileti gövdesinde yeni verilerle birlikte bir HTTP yanıtı ve 200 (Tamam) durum kodu döndürmelidir.

  • İstenen veriler artık mevcut değilse web API'si, 404 (Bulunamadı) durum kodu ile bir HTTP yanıtı döndürmelidir.

  • İstemci, önbelleği korumak için durum kodunu kullanır. Veriler değişmemişse (304 durum kodu), nesne önbelleğe alınmış olarak kalır ve istemci uygulama nesnenin bu sürümünü kullanmaya devam etmelidir. Veriler değişmişse (200 durum kodu), önbelleğe alınmış nesne atılmalı ve yeni bir nesne eklenmelidir. Veriler artık mevcut değilse (404 durum kodu) nesne önbellekten kaldırılmalıdır.

Not

Yanıt üst bilgisi Cache-Control üst bilgisi no-store değerini içeriyorsa, HTTP durum koduna bakılmaksızın nesne her zaman önbellekten kaldırılmalıdır.

Aşağıdaki kod, FindOrderByID If-None-Match üst bilgisini destekleyecek şekilde genişletilmiş yöntemini gösterir. If-None-Match üst bilgisi çıkarılırsa belirtilen sıranın her zaman alındığına dikkat edin:

public class OrdersController : ApiController
{
    [Route("api/orders/{id:int:min(0)}")]
    [HttpGet]
    public IHttpActionResult FindOrderByID(int id)
    {
        try
        {
            // Find the matching order
            Order order = ...;

            // If there is no such order then return NotFound
            if (order == null)
            {
                return NotFound();
            }

            // Generate the ETag for the order
            var hashedOrder = order.GetHashCode();
            string hashedOrderEtag = $"\"{hashedOrder}\"";

            // Create the Cache-Control and ETag headers for the response
            IHttpActionResult response;
            var cacheControlHeader = new CacheControlHeaderValue();
            cacheControlHeader.Public = true;
            cacheControlHeader.MaxAge = new TimeSpan(0, 10, 0);
            var eTag = new EntityTagHeaderValue(hashedOrderEtag);

            // Retrieve the If-None-Match header from the request (if it exists)
            var nonMatchEtags = Request.Headers.IfNoneMatch;

            // If there is an ETag in the If-None-Match header and
            // this ETag matches that of the order just retrieved,
            // then create a Not Modified response message
            if (nonMatchEtags.Count > 0 &&
                String.CompareOrdinal(nonMatchEtags.First().Tag, hashedOrderEtag) == 0)
            {
                response = new EmptyResultWithCaching()
                {
                    StatusCode = HttpStatusCode.NotModified,
                    CacheControlHeader = cacheControlHeader,
                    ETag = eTag
                };
            }
            // Otherwise create a response message that contains the order details
            else
            {
                response = new OkResultWithCaching<Order>(order, this)
                {
                    CacheControlHeader = cacheControlHeader,
                    ETag = eTag
                };
            }

            return response;
        }
        catch
        {
            return InternalServerError();
        }
    }
...
}

Bu örnek EmptyResultWithCaching adlı ek bir özel IHttpActionResult sınıfını içerir. Bu sınıf, yanıt gövdesi içermeyen bir HttpResponseMessage nesnesinin çevresinde sarmalayıcı olarak görev yapar:

public class EmptyResultWithCaching : IHttpActionResult
{
    public CacheControlHeaderValue CacheControlHeader { get; set; }
    public EntityTagHeaderValue ETag { get; set; }
    public HttpStatusCode StatusCode { get; set; }
    public Uri Location { get; set; }

    public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response = new HttpResponseMessage(StatusCode);
        response.Headers.CacheControl = this.CacheControlHeader;
        response.Headers.ETag = this.ETag;
        response.Headers.Location = this.Location;
        return response;
    }
}

İpucu

Bu örnekte veriler için ETag değeri, temel alınan veri kaynağından alınan verilerin karması oluşturularak üretilir. ETag başka bir şekilde hesaplanabiliyorsa, işlem daha fazla iyileştirilebilir ve verilerin yalnızca değişmişse veri kaynağından getirilmesi gerekir. Bu yaklaşım özellikle veriler büyükse veya veri kaynağına erişim önemli bir gecikme süresine neden oluyorsa (örneğin, veri kaynağı bir uzak veritabanı ise) yararlıdır.

İyimser Eşzamanlılığı Desteklemek için ETag’ler Kullanma

HTTP protokolü daha önce önbelleğe alınmış verileri etkinleştirmek için bir iyimser eşzamanlılık stratejisini destekler. Bir kaynağı getirip önbelleğe aldıktan sonra istemci uygulaması kaynağı değiştirmek veya kaldırmak için bir PUT veya DELETE isteği gönderirse, ETag'e başvuran bir If-Match üst bilgisi içermelidir. Web API’si daha sonra bu bilgileri kullanarak kaynağın alındıktan sonra başka bir kullanıcı tarafından değiştirilip değiştirilmediğini belirleyebilir ve istemci uygulamaya aşağıdaki gibi uygun bir yanıt gönderebilir:

  • İstemci, bir If-Match HTTP üst bilgisinde başvurulan kaynağın o anda önbelleğe alınan sürümü için kaynağın yeni ayrıntılarını ve ETag içeren bir PUT isteği oluşturur. Aşağıdaki örnekte bir siparişi güncelleştiren PUT isteği gösterilmektedir:

    PUT https://adventure-works.com/orders/1 HTTP/1.1
    If-Match: "2282343857"
    Content-Type: application/x-www-form-urlencoded
    Content-Length: ...
    productID=3&quantity=5&orderValue=250
    
  • Web API’sindeki PUT işlemi, istenen veriler için geçerli ETag’i alır (yukarıdaki örnekte sipariş 1) ve If-Match üst bilgisindeki değerle karşılaştırır.

  • İstenen veriler için geçerli ETag, istek tarafından sağlanan ETag ile eşleşiyorsa kaynak değişmemiştir ve web API’si 204 (İçerik Yok) HTTP durum kodu ile bir ileti döndürerek güncelleştirmeyi gerçekleştirmelidir. Yanıt, kaynağın güncelleştirilmiş sürümü için Cache-Control ve ETag üst bilgilerini içerebilir. Yanıt her zaman yeni güncelleştirilmiş kaynağın URI'sine başvuran Location üst bilgisini içermelidir.

  • İstenen veriler için geçerli ETag, istek tarafından sağlanan ETag ile eşleşmiyorsa veriler getirildikten sonra başka bir kullanıcı tarafından değiştirilmiştir ve web API’si, boş bir ileti gövdesi ile bir HTTP yanıtı ve 412 (Önkoşul Başarısız) durum kodu döndürmelidir.

  • Güncelleştirilecek kaynak artık mevcut değilse web API'si, 404 (Bulunamadı) durum kodu ile bir HTTP yanıtı döndürmelidir.

  • İstemci, önbelleği korumak için durum kodunu ve yanıt üst bilgilerini kullanır. Veriler güncelleştirilmişse (204 durum kodu), nesne önbelleğe alınmış olarak kalır (Cache-Control üstbilgisi no-store değerini belirtmediği sürece) ancak ETag değerinin güncelleştirilmesi gerekir. Veriler başka bir kullanıcı tarafından değiştirildiyse (durum kodu 412) veya bulunamazsa (durum kodu 404) önbelleğe alınan nesne atılmalıdır.

Sonraki kod örneğinde Orders denetleyicisinin PUT işlemine ait uygulama gösterilmektedir:

public class OrdersController : ApiController
{
    [HttpPut]
    [Route("api/orders/{id:int}")]
    public IHttpActionResult UpdateExistingOrder(int id, DTOOrder order)
    {
        try
        {
            var baseUri = Constants.GetUriFromConfig();
            var orderToUpdate = this.ordersRepository.GetOrder(id);
            if (orderToUpdate == null)
            {
                return NotFound();
            }

            var hashedOrder = orderToUpdate.GetHashCode();
            string hashedOrderEtag = $"\"{hashedOrder}\"";

            // Retrieve the If-Match header from the request (if it exists)
            var matchEtags = Request.Headers.IfMatch;

            // If there is an ETag in the If-Match header and
            // this ETag matches that of the order just retrieved,
            // or if there is no ETag, then update the Order
            if (((matchEtags.Count > 0 &&
                String.CompareOrdinal(matchEtags.First().Tag, hashedOrderEtag) == 0)) ||
                matchEtags.Count == 0)
            {
                // Modify the order
                orderToUpdate.OrderValue = order.OrderValue;
                orderToUpdate.ProductID = order.ProductID;
                orderToUpdate.Quantity = order.Quantity;

                // Save the order back to the data store
                // ...

                // Create the No Content response with Cache-Control, ETag, and Location headers
                var cacheControlHeader = new CacheControlHeaderValue();
                cacheControlHeader.Private = true;
                cacheControlHeader.MaxAge = new TimeSpan(0, 10, 0);

                hashedOrder = order.GetHashCode();
                hashedOrderEtag = $"\"{hashedOrder}\"";
                var eTag = new EntityTagHeaderValue(hashedOrderEtag);

                var location = new Uri($"{baseUri}/{Constants.ORDERS}/{id}");
                var response = new EmptyResultWithCaching()
                {
                    StatusCode = HttpStatusCode.NoContent,
                    CacheControlHeader = cacheControlHeader,
                    ETag = eTag,
                    Location = location
                };

                return response;
            }

            // Otherwise return a Precondition Failed response
            return StatusCode(HttpStatusCode.PreconditionFailed);
        }
        catch
        {
            return InternalServerError();
        }
    }
    ...
}

İpucu

If-Match üst bilgisinin kullanılması tamamen isteğe bağlı ise ve kullanılmazsa, web API’si her zaman belirtilen siparişi güncelleştirmeyi dener ve muhtemelen farkında olmadan başka bir kullanıcı tarafından yapılan güncelleştirmenin üzerine yazar. Kayıp güncelleştirmelerden kaynaklanan sorunları önlemek için her zaman bir If-Match üst bilgisi sağlayın.

Büyük istekleri ve yanıtları işleme

bir istemci uygulamasının boyutu birkaç megabayt (veya daha büyük) olabilecek verileri gönderen veya alan istekler göndermesi gereken durumlar olabilir. Bu miktarda verilerin aktarılmasını beklemek, istemci uygulamanın yanıt vermemesine neden olabilir. Büyük miktarda veriler içeren istekleri işlemeniz gerektiğinde aşağıdaki noktaları göz önünde bulundurun:

Büyük nesneler içeren istek ve yanıtları en iyi duruma getirme

Bazı kaynaklar büyük nesneler olabilir veya grafik görüntüleri veya diğer ikili veri türleri gibi büyük alanlar içerebilir. Bu kaynakların en iyi şekilde karşıya yüklenmesini ve indirilmesini sağlamak üzere web API’si akışı desteklemelidir.

HTTP protokolü, büyük veri nesnelerini istemciye akışla geri aktarmak için öbekli aktarım kodlama mekanizması sağlar. İstemci büyük bir nesne için bir HTTP GET isteği gönderdiğinde, web API’si yanıtı bir HTTP bağlantısı üzerinden öbek parçaları halinde geri gönderebilir. Yanıttaki verilerin uzunluğu başlangıçta bilinmiyor olabilir (oluşturulabilir), bu nedenle web API'sini barındıran sunucu, Content-Length üst bilgisi yerine üst bilgiyi belirten Transfer-Encoding: Chunked her öbekle bir yanıt iletisi göndermelidir. İstemci uygulama her bir öbeği sırasıyla alıp tam yanıtı oluşturabilir. Sunucu sıfır boyuta sahip bir son öbeği geri gönderdiğinde veri aktarımı tamamlanır.

Tek bir istek, önemli miktarda kaynak tüketen çok büyük bir nesne ile sonuçlanabilir. Akış işlemi sırasında web API'si bir istekteki veri miktarının kabul edilebilir bazı sınırları aştığını belirlerse, işlemi durdurabilir ve durum kodu 413 (İstek Varlığı Çok Büyük) olan bir yanıt iletisi döndürebilir.

HTTP sıkıştırmasını kullanarak, ağ üzerinden aktarılan büyük nesnelerin boyutunu en aza indirebilirsiniz. Bu yaklaşım, ağ trafiği miktarını ve ilişkili ağ gecikmesini azaltmaya yardımcı olur ancak istemcide ve web API’sini barındıran sunucuda ek işleme gerektirir. Örneğin, sıkıştırılmış verileri almayı bekleyen bir istemci uygulaması bir Accept-Encoding: gzip istek üst bilgisi içerebilir (diğer veri sıkıştırma algoritmaları da belirtilebilir). Sunucu sıkıştırmayı destekliyorsa, ileti gövdesinde ve Content-Encoding: gzip yanıt üst bilgisinde gzip biçiminde tutulan içerikle yanıt vermelidir.

Kodlanmış sıkıştırmayı akışla birleştirebilirsiniz; verileri akışla aktarmadan önce sıkıştırabilir ve ileti üst bilgilerinde gzip içerik kodlaması ile öbekli aktarım kodlamasını belirtebilirsiniz. Ayrıca bazı web sunucularının (örneğin, Internet Information Server), web API’sinin verileri sıkıştırıp sıkıştırmadığına bakılmaksızın HTTP yanıtlarını otomatik olarak sıkıştıracak şekilde yapılandırılabileceğini unutmayın.

Zaman uyumsuz işlemleri desteklemeyen istemciler için kısmi yanıtlar uygulama

Bir istemci uygulama, zaman uyumsuz akışa alternatif olarak büyük nesneler için öbekler halinde açıkça veri isteyebilir. Bu duruma kısmi yanıt adı verilir. İstemci uygulama, nesne hakkında bilgi almak için bir HTTP HEAD isteği gönderir. Web API'si kısmi yanıtları destekliyorsa HEAD isteğine üst bilgi ve nesnenin toplam boyutunu gösteren bir üst bilgi içeren bir Accept-RangesContent-Length yanıt iletisiyle yanıt vermelidir, ancak iletinin gövdesi boş olmalıdır. İstemci uygulama, alınacak bayt aralığını belirtmek üzere bir dizi GET isteği oluşturmak için bu bilgileri kullanabilir. Web API'sinin HTTP durumu 206 (Kısmi İçerik) olan bir yanıt iletisi, yanıt iletisinin gövdesinde yer alan gerçek veri miktarını belirten content-length üst bilgisi ve bu verilerin temsil ettiği nesnenin hangi bölümünü (bayt sayısı gibi 40008000) gösteren bir İçerik Aralığı üst bilgisi döndürmesi gerekir.

HTTP HEAD istekleri ve kısmi yanıtlar API tasarımında daha ayrıntılı olarak açıklanmıştır.

İstemci uygulamalarda gereksiz 100-Continue durum iletileri göndermekten kaçınma

Bir sunucuya büyük miktarda veri göndermek üzere olan bir istemci uygulama, ilk olarak sunucunun isteği kabul etmek için gerçekten istekli olup olmadığını belirleyebilir. İstemci uygulama, verileri göndermeden önce Expect: 100-Continue üst bilgisi, verilerin boyutunu belirten bir Content-Length üst bilgisi ve boş bir ileti gövdesi ile HTTP isteği gönderebilir. Sunucu isteği işlemek için istekliyse, 100 (Devam) HTTP durumunu belirten bir ileti ile yanıt vermelidir. İstemci uygulama daha sonra devam edip ileti gövdesine verileri ekleyerek tam isteği gönderebilir.

IIS kullanarak bir hizmet barındırıyorsanız, HTTP.sys sürücüsü istekleri web uygulamanıza geçirmeden önce Bekleme: 100-Devam üst bilgilerini otomatik olarak algılar ve işler. Bu durum, bu üst bilgileri uygulama kodunuzda görme olasılığınızın düşük olduğu anlamına gelir ve IIS’nin uygunsuz ya da çok büyük olarak kabul ettiği tüm iletileri filtrelediğini varsayabilirsiniz.

.NET Framework kullanarak istemci uygulamaları oluşturursanız, tüm POST ve PUT iletileri ilk olarak Varsayılan olarak Expect: 100-Continue üst bilgilerine sahip iletiler gönderir. Sunucu tarafında olduğu gibi işlem, .NET Framework tarafından şeffaf bir şekilde ele alınır. Ancak, bu işlem her bir POST ve PUT isteğinin küçük istekler için bile sunucuya iki gidiş dönüş oluşturması ile sonuçlanır. Uygulamanız büyük miktarda veriler içeren istekler göndermiyorsa, istemci uygulamada ServicePoint nesneleri oluşturmak için ServicePointManager sınıfını kullanarak bu özelliği devre dışı bırakabilirsiniz. Bir ServicePoint nesnesi, istemcinin bir düzene göre sunucu ile kurduğu bağlantıları ve sunucu üzerindeki kaynakları tanımlayan URI’lerin konak parçalarını işler. Bundan sonra Expect100Continue nesnesinin ServicePoint özelliğini false olarak ayarlayabilirsiniz. İstemci tarafından ServicePoint nesnesine ait düzen ve konak parçaları ile eşleşen bir URI aracılığıyla daha sonra yapılan tüm POST ve PUT istekleri, Expect: 100-Continue üst bilgileri olmadan gönderilir. Aşağıdaki kod, bir http düzeni ve bir www.contoso.com konağı ile URI’lere gönderilen tüm istekleri yapılandıran bir ServicePoint nesnesini yapılandırma işlemini göstermektedir.

Uri uri = new Uri("https://www.contoso.com/");
ServicePoint sp = ServicePointManager.FindServicePoint(uri);
sp.Expect100Continue = false;

Sınıfın statik Expect100Continue özelliğini ServicePointManager , daha sonra oluşturulan tüm ServicePoint nesneleri için bu özelliğin varsayılan değerini belirtmek üzere de ayarlayabilirsiniz.

Çok sayıda nesne döndürebilen istekler için sayfalandırmayı destekleme

Bir koleksiyon çok sayıda kaynak içeriyorsa, karşılık gelen URI’ye bir GET isteğinin düzenlenmesi web API’sini barındıran sunucuda performansı etkileyerek önemli işlem yüküyle sonuçlanabilir ve gecikme süresini artıran önemli miktarda ağ trafiği oluşturabilir.

Bu sorunları ele almak için web API’si, istemci uygulamanın istekleri daha kolay yönetilebilir, farklı bloklar (veya sayfalar) halinde daraltmasını sağlayan sorgu dizelerini desteklemelidir. Aşağıdaki kod, denetleyicideki Orders yöntemini gösterirGetAllOrders. Bu yöntem, siparişlerin ayrıntılarını alır. Bu yöntem kısıtlanmamışsa büyük miktarda veri döndürebilir. limit ve offset parametreleri, veri hacmini daha küçük bir alt kümeye indirgemeye (bu örnekte varsayılan olarak ilk 10 sipariş) yöneliktir:

public class OrdersController : ApiController
{
    ...
    [Route("api/orders")]
    [HttpGet]
    public IEnumerable<Order> GetAllOrders(int limit=10, int offset=0)
    {
        // Find the number of orders specified by the limit parameter
        // starting with the order specified by the offset parameter
        var orders = ...
        return orders;
    }
    ...
}

Bir istemci uygulama, https://www.adventure-works.com/api/orders?limit=30&offset=50 URI’sini kullanarak 50 uzaklıktan başlayarak 30 siparişi almak üzere bir istek gönderebilir.

İpucu

İstemci uygulamaların 2000 karakterden uzun bir URI ile sonuçlanan sorgu dizeleri belirtmesini önleyin. Birçok web istemcisi ve sunucusu bu kadar uzun URI'leri işleyemez.

Yanıt hızı, ölçeklenebilirlik ve kullanılabilirliği sürdürme

Aynı web API'si dünyanın herhangi bir yerinde çalışan birçok istemci uygulaması tarafından kullanılabilir. Ağır bir yük altında yanıt hızını korumak, yüksek oranda değişen bir iş yükünü destekleyecek şekilde ölçeklenebilir olmak ve kritik iş işlemleri gerçekleştiren istemciler için kullanılabilirliği garanti etmek amacıyla web API’sinin uygulandığından emin olmak gerekir. Bu gereksinimlerin nasıl karşılanacağını belirlerken aşağıdaki noktaları göz önünde bulundurun:

Uzun süreli istekler için zaman uyumsuz destek sağlama

İşlenmesi uzun sürebilecek bir istek, isteği gönderen istemciyi engellemeden gerçekleştirilmelidir. Web API’si isteği doğrulamak üzere bazı ilk denetimler gerçekleştirebilir, işi gerçekleştirmek üzere ayrı bir görev başlatabilir ve sonra 202 (Kabul Edildi) HTTP kodu ile bir yanıt iletisi döndürebilir. Görev web API'si kapsamında zaman uyumsuz olarak çalışabilir veya bir arka plan görevine boşaltılabilir.

Web API’si ayrıca işleme sonuçlarını istemci uygulamaya döndüren bir mekanizma sağlamalıdır. İstemci uygulamaların işlemenin tamamlanıp tamamlanmadığını düzenli aralıklarla sorgulayıp sonucu almasına yönelik bir yoklama mekanizması sağlayarak ya da işlem tamamlandığında web API’sinin bir bildirim göndermesini sağlayarak bunu gerçekleştirebilirsiniz.

Aşağıdaki yaklaşımı kullanarak, sanal bir kaynak olarak hareket eden bir yoklama URI’si sağlama yoluyla basit bir yoklama mekanizması uygulayabilirsiniz:

  1. İstemci uygulama, ilk isteği web API’sine gönderir.
  2. Web API'si, istekle ilgili bilgileri Azure Tablo Depolama veya Microsoft Azure Cache'te tutulan bir tabloda depolar ve bu giriş için büyük olasılıkla GUID biçiminde benzersiz bir anahtar oluşturur. Alternatif olarak, istek ve benzersiz anahtar hakkındaki bilgileri içeren bir ileti de Azure Service Bus aracılığıyla gönderilebilir.
  3. Web API'si işlemeyi ayrı bir görev olarak veya Hangfire gibi bir kitaplıkla başlatır. Web API'si, görevin durumunu tabloya Çalışıyor olarak kaydeder.
    • Azure Service Bus kullanıyorsanız ileti işleme, büyük olasılıkla Azure İşlevleri veya AKS kullanılarak API'den ayrı olarak gerçekleştirilir.
  4. Web API'si HTTP durum kodu 202 (Kabul Edildi) ve /polling/{guid} gibi oluşturulan benzersiz anahtarı içeren bir URI içeren bir yanıt iletisi döndürür.
  5. Görev tamamlandığında, web API'si sonuçları tabloda depolar ve görevin durumunu Tamamlandı olarak ayarlar. Görev başarısız olursa web API’sinin hatayla ilgili bilgileri de depolayabileceğini ve durumu Başarısız olarak ayarlayabileceğini unutmayın.
    • Olası geçici hataları çözmek için yeniden deneme tekniklerini uygulamayı göz önünde bulundurun.
  6. Görev çalıştırılırken istemci kendi işlemini gerçekleştirmeye devam edebilir. Daha önce aldığı URI'ye düzenli aralıklarla istek gönderebilir.
  7. URI'deki web API'si, tablodaki karşılık gelen görevin durumunu sorgular ve bu durumu içeren HTTP durum kodu 200 (Tamam) içeren bir yanıt iletisi döndürür (Çalışıyor, Tamamlandı veya Başarısız). Görev tamamlandıysa veya başarısız olduysa, yanıt iletisi işlemin sonuçlarını veya hata nedeniyle ilgili mevcut tüm bilgileri de içerebilir.
    • Uzun süre çalışan işlemin daha fazla ara durumu varsa, NServiceBus veya MassTransit gibi saga desenini destekleyen bir kitaplık kullanmak daha iyidir.

Bildirimleri uygulama seçenekleri şunlardır:

  • İstemci uygulamalarına zaman uyumsuz yanıtlar göndermek için bildirim hub'ı kullanma. Daha fazla bilgi için bkz . Azure Notification Hubs kullanarak belirli kullanıcılara bildirim gönderme.
  • İstemci ile web API’sini barındıran sunucu arasında kalıcı bir ağ bağlantısı sürdürmek üzere Comet modelini kullanma ve bu bağlantıyı kullanarak sunucudan istemciye iletileri geri gönderme. Building a Simple Comet Application in the Microsoft .NET Framework (Microsoft .NET Framework’te Basit Bir Comet Uygulaması Derleme) adlı MSDN dergisi makalesinde örnek bir çözüm açıklanmaktadır.
  • Kalıcı bir ağ bağlantısı üzerinden verileri web sunucusundan istemciye gerçek zamanlı olarak göndermek için SignalR kullanma. SignalR, bir NuGet paketi olarak ASP.NET web uygulamaları için kullanılabilir. ASP.NET SignalR web sitesinde daha fazla bilgi bulabilirsiniz.

Her isteğin durum bilgisiz olduğundan emin olma

Her isteğin atomik olduğu kabul edilmelidir. Bir istemci uygulama tarafından yapılan istek ile aynı istemcinin gönderdiği sonraki istekler arasında bir bağımlılık olmamalıdır. Bu yaklaşım ölçeklenebilirliğe yardımcı olur; web hizmetinin örnekleri birkaç sunucuya üzerinde dağıtılabilir. İstemci istekleri bu örneklerin herhangi birine yönlendirilebilir ve sonuçlar her zaman aynı olmalıdır. Ayrıca, benzer bir nedenle kullanılabilirliği artırır; bir web sunucusu başarısız olursa, istemci uygulamalara olumsuz bir etkisi olmadan sunucu yeniden başlatılırken istekler başka bir örneğe yönlendirilebilir (Azure Traffic Manager kullanılarak).

DoS saldırılarının olasılığını azaltmak için istemcileri izleme ve azaltma uygulama

Belirli bir istemci belirli bir süre içinde çok sayıda istek yaparsa, hizmeti sadece kendi yönetimine alıp diğer istemcilerin performansını etkileyebilir. Bu sorunu gidermek için web API’si tüm gelen isteklerin IP adresini izleyerek veya kimliği doğrulanmış her erişimi günlüğe kaydederek istemci uygulamalardan gelen çağrıları izleyebilir. Bu bilgileri, kaynak erişimini sınırlamak için kullanabilirsiniz. Bir istemci tanımlı bir sınırı aşarsa, web API’si 503 (Hizmet Kullanılamıyor) durumu ile bir yanıt iletisi döndürebilir ve istemcinin reddedilmeden sonraki isteği ne zaman gönderebileceğini belirten bir Retry-After üst bilgisi ekleyebilir. Bu strateji, sistemi geciktiren bir istemci kümesinden Hizmet Reddi (DoS) saldırısı olasılığını azaltmaya yardımcı olabilir.

Kalıcı HTTP bağlantılarını dikkatli bir şekilde yönetme

HTTP protokolü, kullanılabilir olduğu durumlarda kalıcı HTTP bağlantılarını destekler. HTTP 1.0 belirtimi, istemci uygulamasının sunucuya yenilerini açmak yerine sonraki istekleri göndermek için aynı bağlantıyı kullanabileceğini belirtmesini sağlayan Bağlan ion:Keep-Alive üst bilgisini ekledi. İstemci, konak tarafından tanımlanan bir süre içinde bağlantıyı yeniden kullanmazsa bağlantı otomatik olarak kapanır. Bu davranış, Azure hizmetleri tarafından HTTP 1.1’de kullanılan varsayılan davranıştır; bu nedenle, iletilere Keep-Alive üst bilgilerini eklemek gerekmez.

Bağlantının açık tutulması, gecikme süresi ve ağ tıkanıklığını azaltarak yanıt süresini iyileştirmeye yardımcı olabilir, ancak gereksiz bağlantıları gerekenden daha uzun süre açık tutup diğer eşzamanlı istemcilerin bağlantı kurma becerisini sınırlayarak ölçeklenebilirliğe zarar verebilir. Ayrıca, istemci uygulama bir mobil cihazda çalışıyorsa pil ömrünü etkileyebilir; uygulama sunucuya yalnızca ara sıra istek gönderiyorsa, bağlantının açık tutulması pilin daha hızlı boşalmasına neden olabilir. Bir bağlantının HTTP 1.1 ile kalıcı hale getirilmediğinden emin olmak için istemci, varsayılan davranışı geçersiz kılmak üzere iletilere bir Connection:Close üst bilgisi ekleyebilir. Benzer şekilde, bir sunucu çok fazla sayıda istemciyi işliyorsa, yanıt iletilerine Connection:Close üst bilgisini ekleyerek bağlantıyı kapatması ve sunucu kaynaklarını koruması gerekir.

Not

Kalıcı HTTP bağlantıları, tekrarlayarak bir iletişim kanalı kurma ile ilişkili ağ yükünü azaltmaya yönelik tamamen isteğe bağlı bir özelliktir. Ne web API’sinin ne de istemcinin kullanılabilir olması, kalıcı bir HTTP bağlantısına bağlı olmalıdır. Comet stili bildirim sistemlerini uygulamak için kalıcı HTTP bağlantıları kullanmayın; bunun yerine TCP katmanında yuvalar (veya varsa web yuvaları) kullanmanız gerekir. Son olarak, istemci uygulama bir suucu ile ara sunucu üzerinden iletişim kuruyorsa Keep-Alive üst bilgilerinin sınırlı kullanıma sahip olduğunu unutmayın. Yalnızca istemci ve ara sunucu içeren bağlantı kalıcı olur.

Web API’si yayımlama ve yönetme

Bir web API’sini istemci uygulamalar için kullanılabilir hale getirmek üzere web API’sinin bir ana bilgisayar ortamına dağıtılması gerekir. Bu ortam diğer türdeki ana bilgisayar işlemlerinden bazıları olabilse de, genellikle bir web sunucusudur. Bir web API'sini yayımlarken aşağıdaki noktaları dikkate almanız gerekir:

  • Tüm istekler kimlik doğrulamasından geçmiş ve yetkilendirilmiş olmalı ve uygun düzeyde erişim denetimi uygulanmalıdır.
  • Ticari bir web API’si, yanıt süreleriyle ilgili çeşitli kalite garantilerine tabi olabilir. Yük zaman içinde önemli ölçüde farklılık gösterebiliyorsa konak ortamının ölçeklenebilir olduğundan emin olmak önemlidir.
  • Gelir elde etme amacıyla isteklerin ölçülmesi gerekebilir.
  • Web API’sine trafik akışının düzenlenmesi ve kotalarını tüketmiş belirli istemciler için ağ kapasitesinin azaltılması gerekebilir.
  • Yasal düzenlemeler tüm istek ve yanıtların kaydedilmesini ve denetlenmesini zorunlu kılabilir.
  • Kullanılabilirliği sağlamak için, web API’sini barındıran sunucunun durumunun izlenmesi ve gerekirse yeniden başlatılması gerekebilir.

Bu sorunları web API'sinin uygulanmasıyla ilgili teknik sorunlardan ayrıştırabilmek yararlıdır. Bu nedenle, ayrı işlem olarak çalışan ve istekleri web API’sine yönlendiren bir cephe oluşturmayı düşünün. Cephe, yönetim işlemlerini sağlayabilir ve doğrulanmış istekleri web API’sine iletebilir. Cephe kullanılması aşağıdaki gibi çok sayıda işlevsel avantaj da sağlayabilir:

  • Birden çok web API'si için tümleştirme noktası olarak hareket etme.
  • Çeşitli teknolojiler kullanılarak oluşturulan istemciler için iletileri dönüştürme ve iletişim protokollerini çevirme.
  • Web API’sini barındıran sunucu üzerindeki yükü azaltmak üzere istekleri ve yanıtları önbelleğe alma.

Web API'sini test etme

Bir web API’si, yazılımın herhangi bir kısmı kadar ayrıntılı bir şekilde test edilmelidir. İşlevselliği doğrulamak için birim testleri oluşturmayı düşünmelisiniz.

Bir web API'sinin doğası, düzgün çalıştığını doğrulamak için kendi ek gereksinimlerini getirir. Aşağıdaki durumlara özellikle dikkat etmeniz gerekir:

  • Doğru işlemleri çağırdığını onaylamak üzere tüm yolları test edin. Bir yol ile bu yola gönderilebilen HTTP yöntemleri (GET, POST, PUT, DELETE) arasında bir uyumsuzluk olduğunu gösterebileceği için, beklenmedik şekilde döndürülen 405 (Yönteme İzin Verilmiyor) HTTP durum koduna özellikle dikkat edin.

    Belirli bir kaynağa POST isteği gönderme gibi, bunları desteklemeyen yollara HTTP istekleri gönderin (POST istekleri yalnızca kaynak koleksiyonlarına gönderilmelidir). Bu durumlarda tek geçerli yanıt 405 (İzin Verilmiyor) durum kodu olmalıdır.

  • Tüm yolların uygun şekilde korunduğunu ve uygun kimlik doğrulama ile yetkilendirme denetimlerine tabi olduğunu doğrulayın.

    Not

    Kullanıcı kimlik doğrulaması gibi bazı güvenlik yönlerinin web API’si yerine ana bilgisayar ortamının sorumluluğunda olması daha yüksek bir olasılıktır, ancak yine de dağıtım işlemine güvenlik testlerinin dahil edilmesi gerekir.

  • Her bir işlem tarafından gerçekleştirilen özel durum işlemeyi test edin ve istemci uygulamaya uygun ve anlamlı bir HTTP yanıtının geri gönderildiğini doğrulayın.

  • İstek ve yanıt iletilerinin doğru oluşturulduğunu onaylayın. Örneğin, bir HTTP POST isteği yeni bir kaynağın verilerini x-www-form-urlencoded biçiminde içeriyorsa, karşılık gelen işlemin verileri doğru şekilde ayıkladığını, kaynakları oluşturduğunu ve doğru Location üst bilgisi dahil olmak üzere yeni kaynağın ayrıntılarını içeren bir yanıt döndürdüğünü onaylayın.

  • Yanıt iletilerindeki tüm bağlantıları ve URI'leri doğrulayın. Örneğin, bir HTTP POST iletisi yeni oluşturulan kaynağın URI'sini döndürmelidir. Tüm HATEOAS bağlantıları geçerli olmalıdır.

  • Her işlemin farklı giriş birleşimleri için doğru durum kodlarını döndürdüğünden emin olun. Örneğin:

    • Bir sorgu başarılı olursa, 200 (Tamam) durum kodunu döndürmelidir
    • Bir kaynak bulunamıyorsa, işlem 404 (Bulunamadı) HTTP durum kodunu döndürmelidir.
    • İstemci bir kaynağı başarıyla silen bir istek gönderirse durum kodu 204 (İçerik Yok) olmalıdır.
    • İstemci yeni bir kaynak oluşturan bir istek gönderirse, durum kodu 201 (Oluşturuldu) olmalıdır.

5xx aralığında beklenmedik yanıt durum kodlarına dikkat edin. Bu iletiler genellikle geçerli bir isteği yerine getiremediğini belirtmek üzere ana bilgisayar sunucusu tarafından raporlanır.

  • Bir istemci uygulamanın belirtebildiği farklı istek üst bilgisi birleşimlerini test edin ve web API’sinin yanıt iletilerinde beklenen bilgileri döndürdüğünden emin olun.

  • Sorgu dizelerini test edin. Bir işlem isteğe bağlı parametreler (örneğin, sayfalandırma istekleri) alabiliyorsa, parametrelerin farklı birleşimlerini ve sırasını test edin.

  • Zaman uyumsuz işlemlerin başarıyla tamamlandığını doğrulayın. Web API’si büyük ikili nesneler (video veya ses gibi) döndüren istekler için akış yapmayı destekliyorsa, veriler akışla aktarılırken istemci isteklerinin engellenmediğinden emin olun. Web API'si uzun süre çalışan veri değiştirme işlemleri için yoklama uygularsa, işlemlerin devam ederken durumlarını doğru bildirdiğini doğrulayın.

Ayrıca, web API’sinin zorlama altında tatmin edici bir şekilde çalışıp çalışmadığını denetlemek için performans testleri oluşturup çalıştırmanız gerekir. Visual Studio Ultimate’ı kullanarak bir web performansı ve yük testi projesi oluşturabilirsiniz.

Azure API Management’ı Kullanma

Azure'da, web API'sini yayımlamak ve yönetmek için Azure API Management'ı kullanmayı göz önünde bulundurun. Bu özelliği kullanarak, bir veya daha fazla web API’si için cephe olarak davranan bir hizmet oluşturabilirsiniz. Hizmet, Azure portalını kullanarak oluşturabileceğiniz ve yapılandırabileceğiniz ölçeklenebilir bir web hizmetidir. Bu hizmeti kullanarak bir web API’sini aşağıdaki gibi yayımlayıp yönetebilirsiniz:

  1. Web API’sini bir web sitesine, Azure bulut hizmetine veya Azure sanal makinesine dağıtın.

  2. API yönetim hizmetini web API'sine bağlayın. Yönetim API’sinin URL’sine gönderilen istekler, web API’sindeki URI’ler ile eşlenir. Aynı API yönetimi hizmeti, istekleri birden fazla web API’sine yönlendirebilir. Bunun yapılması, birden fazla web API’sini tek bir yönetim hizmetinde toplamanıza olanak tanır. Benzer şekilde, farklı uygulamaların kullanabileceği işlevleri kısıtlamanız veya bölmeniz gerekirse aynı web API’sine birden fazla API yönetim hizmetinden başvurulabilir.

    Not

    HTTP GET isteklerine yönelik yanıtın bir parçası olarak oluşturulan HATEOAS bağlantılarındaki URI'ler, web API'sini barındıran web sunucusuna değil API yönetim hizmetinin URL'sine başvurmalıdır.

  3. Her bir web API’si için web API’sinin işleme giriş olarak eklenebilecek isteğe bağlı parametrelerle birlikte kullanıma sunduğu HTTP işlemlerini belirtin. API yönetim hizmetinin aynı verilere yönelik tekrarlayan istekleri en iyi duruma getirmek üzere web API’sinden alınan yanıtı önbelleğe alıp almayacağını da yapılandırabilirsiniz. Her bir işlemin oluşturabileceği HTTP yanıtlarının ayrıntılarını kaydedin. Bu bilgiler geliştiricilere yönelik belgeler oluşturmak için kullanılır, bu nedenle doğru ve eksiksiz olması önemlidir.

    Azure portalı tarafından sağlanan sihirbazları kullanarak işlemleri el ile tanımlayabilir veya wadl veya Swagger biçiminde tanımları içeren bir dosyadan içeri aktarabilirsiniz.

  4. API yönetim hizmeti ile web API’sini barındıran web sunucusu arasındaki iletişime yönelik güvenlik ayarlarını yapılandırın. API yönetim hizmeti şu anda sertifika kullanarak Temel kimlik doğrulaması ve karşılıklı kimlik doğrulamanın yanı sıra OAuth 2.0 kullanıcı kimlik doğrulamasını desteklemektedir.

  5. Ürün oluşturma. Ürün, yayın birimidir; daha önce yönetim hizmetine bağladığınız web API’lerini ürüne eklersiniz. Ürün yayımlandığında web API’leri geliştiriciler için kullanılabilir hale gelir.

    Not

    Bir ürün yayımlanmadan önce ürüne erişebilecek kullanıcı grupları tanımlayabilir ve bu gruplara kullanıcı ekleyebilirsiniz. Böylece, web API’sini kullanabilecek geliştiriciler ve uygulamalar üzerinde denetim elde edersiniz. Bir web API’si onaya tabidir; bir geliştiricinin web API’sine erişebilmesi için ürün yöneticisine istek göndermesi gerekir. Yönetici, geliştiriciye erişim verebilir veya erişimi engelleyebilir. Koşulların değişmesi halinde mevcut geliştiriciler de engellenebilir.

  6. Her bir web API'sine yönelik ilkeleri yapılandırın. İlkeler, etki alanları arası çağrılara izin verilip verilmeyeceği, istemci kimliklerinin nasıl doğrulanacağı, XML ile JSON veri biçimleri arasında şeffaf dönüştürme yapılıp yapılmayacağı, belirli bir IP aralığından çağrıların kısıtlanıp kısıtlanmayacağı, kullanım kotaları ve çağrı hızının sınırlanıp sınırlanmayacağı gibi konuları yönetir. İlkeler ürünün tamamına genel olarak, bir üründeki tek bir web API’si için veya bir web API’sindeki tek işlemler için uygulanabilir.

Daha fazla bilgi için API Management belgelerine bakın.

İpucu

Azure, yük devretme ve yük dengeleme işlemlerini uygulamanıza ve farklı coğrafi bölgelerde barındırılan bir web sitesinin birden fazla örneğinde gecikme süresini azaltmanıza olanak tanıyan Azure Traffic Manager’ı sunar. Azure Traffic Manager’ı API Management Hizmeti ile birlikte kullanabilirsiniz; API Management Hizmeti, istekleri Azure Traffic Manager aracılığıyla bir web sitesinin örneklerine yönlendirebilir. Daha fazla bilgi için bkz . Traffic Manager yönlendirme yöntemleri.

Bu yapıda, web siteleriniz için özel DNS adları kullanıyorsanız, her web sitesi için uygun CNAME kaydını Azure Traffic Manager web sitesinin DNS adına işaret eden şekilde yapılandırmanız gerekir.

İstemci tarafı geliştiricileri destekleme

İstemci uygulamalar oluşturan geliştiriciler genellikle web API’sine erişim ile ilgili bilgiler ve web hizmeti ile istemci uygulama arasındaki farklı istek ve yanıtları tanımlayan parametreler, veri türleri, dönüş türleri ve dönüş kodları ile ilgili belgeler gerektirir.

Bir web API’sinin REST işlemlerini belgeleme

Azure API Management Hizmeti bir web API’si tarafından kullanıma sunulan REST işlemlerini tanımlayan bir geliştirici portalı içerir. Bir ürün yayımlandığında bu portalda görüntülenir. Geliştiriciler, erişime kaydolmak için bu portalı kullanabilir; daha sonra yönetici, isteği onaylayabilir veya reddedebilir. Geliştirici onaylanırsa kendisine geliştirdiği istemci uygulamalardan gelen çağrıların kimliğini doğrulamak için kullanılan bir abonelik anahtarı atanır. Bu anahtar her web API çağrısında kullanılmalıdır; aksi takdirde çağrı reddedilir.

Bu portal ayrıca şunları sağlar:

  • Ürünün kullanıma sunduğu işlemleri, gerekli parametreleri ve döndürülebilecek farklı yanıtları listeleyen ürün belgeleri. Bu bilgilerin Microsoft Azure API Management Hizmetini kullanarak web API’si yayımlama bölümünde bulunan listedeki 3. adımda verilen ayrıntılardan oluşturulduğunu unutmayın.
  • JavaScript, C#, Java, Ruby, Python ve PHP dahil olmak üzere birkaç dilden işlemlerin nasıl çağrılacağını gösteren kod parçacıkları.
  • Geliştiricinin üründeki her bir işlemi test etmek ve sonuçları görüntülemek üzere HTTP isteği göndermesini sağlayan geliştirici konsolu.
  • Geliştiricinin bulunan her türlü sorunu bildirebileceği bir sayfa.

Azure portalı, kuruluşunuzun markasıyla eşleşecek şekilde stil ve düzeni değiştirmek için geliştirici portalını özelleştirmenizi sağlar.

İstemci SDK’sını uygulama

Bir web API’sine erişmek üzere REST istekleri çağıran bir istemci uygulamanın derlenmesi, her bir isteği oluşturmak için önemli miktarda kod yazıp uygun şekilde biçimlendirmeyi, isteği web hizmetini barındıran sunucuya göndermeyi ve isteğin başarılı olup olmadığını belirlemek ve döndürülen verileri ayıklamak üzere yanıtı ayrıştırmayı gerektirir. İstemci uygulamayı bu sorunlardan uzak tutmak için REST arabirimini sarmalayan ve bu düşük düzeyli ayrıntıları daha işlevsel bir yöntem kümesinde soyutlayan bir SDK sağlayabilirsiniz. İstemci uygulama, çağrıları saydam bir şekilde REST isteklerine dönüştüren ve sonra yanıtları yeniden yöntem dönüş değerlerine dönüştüren bu yöntemleri kullanır. Bu teknik, Azure SDK’sı dahil birçok hizmet tarafından yaygın olarak uygulanır.

İstemci tarafı SDK oluşturma işlemi tutarlı bir şekilde uygulanması ve dikkatlice test edilmesi gereken önemli bir iştir. Ancak, bu işlemin büyük bölümü mekanik hale getirilebilir ve birçok satıcı bu görevlerin birçoğunu otomatikleştirebilen araçlar sağlar.

Web API'sini izleme

Web API’nizi nasıl yayımlayıp dağıttığınıza bağlı olarak, web API’sini doğrudan izleyebilir veya API Management hizmetinden geçen trafiği analiz ederek kullanım ve sistem durumu bilgilerini toplayabilirsiniz.

Web API'sini doğrudan izleme

Web API’nizi ASP.NET Web API şablonu (bir Web API projesi ya da Azure bulut hizmetinde bir Web rolü olarak) ve Visual Studio 2013 kullanarak uyguladıysanız, ASP.NET Application Insights’ı kullanarak kullanılabilirlik, performans ve kullanım verilerini toplayabilirsiniz. Application Insights, web API’si buluta dağıtıldığında istek ve yanıtlara ilişkin bilgileri şeffaf bir şekilde izleyip kaydeden bir pakettir; paket yüklenip yapılandırıldıktan sonra paketi kullanmak için web API’nizde herhangi bir kodu değiştirmeniz gerekmez. Web API’sini bir Azure web sitesine dağıttığınızda tüm trafik incelenir ve aşağıdaki istatistikler toplanır:

  • Sunucu yanıt süresi.
  • Sunucu isteklerinin sayısı ve her isteğin ayrıntıları.
  • Ortalama yanıt süresi bakımından en yavaş istekler.
  • Başarısız olan isteklerin ayrıntıları.
  • Farklı tarayıcılar ve kullanıcı aracıları tarafından başlatılan oturum sayısı.
  • En sık görüntülenen sayfalar (web API’leri yerine öncelikle web uygulamaları için yararlıdır).
  • Web API’sine erişen farklı kullanıcı rolleri.

Bu verileri Azure portalında gerçek zamanlı olarak görüntüleyebilirsiniz. Ayrıca, web API'sinin durumunu izleyen web testleri de oluşturabilirsiniz. Web testi, web API'sinde belirtilen URI'ye düzenli bir istek gönderir ve yanıtı yakalar. Başarılı bir yanıtın tanımını belirtebilir (HTTP durum kodu 200 gibi) ve istek bu yanıtı döndürmezse yöneticiye gönderilecek bir uyarı ayarlayabilirsiniz. Gerekirse, yönetici başarısız olması durumunda web API’sini barındıran sunucuyu yeniden başlatabilir.

Daha fazla bilgi için bkz. Application Insights - ASP.NET kullanmaya başlama.

API Management Hizmeti aracılığıyla web API’si izleme

Web API'nizi API Management hizmetini kullanarak yayımladıysanız, Azure portalındaki API Management sayfasında hizmetin genel performansını görüntülemenizi sağlayan bir pano bulunur. Analiz sayfası, ürünün kullanımına ilişkin ayrıntılara inmenizi sağlar. Bu sayfa aşağıdaki sekmeleri içerir:

  • Kullanım. Bu sekme, yapılan API çağrılarının sayısı ve zaman içinde bu çağrıları işlemek için kullanılan bant genişliği hakkında bilgi verir. Kullanım ayrıntılarını ürün, API ve işleme göre filtreleyebilirsiniz.
  • Sistem Durumu. Bu sekmeyi kullanarak API isteklerinin sonucunu (döndürülen HTTP durum kodları), önbelleğe alma ilkesinin etkinliğini, API yanıt süresini ve hizmet yanıt süresini görüntüleyebilirsiniz. Sistem durumu verilerini de ürün, API ve işleme göre filtreleyebilirsiniz.
  • Etkinlik. Bu sekme başarılı çağrı, başarısız çağrı, engellenen çağrı, ortalama yanıt süresi ve her bir ürüne ait yanıt süresi, web API’si ve işlem sayısının metin özetini sağlar. Bu sayfa ayrıca her bir geliştirici tarafından yapılan çağrıların sayısını listeler.
  • Bir bakışta. Bu sekme, çoğu API çağrısını yapmaktan sorumlu geliştiriciler dahil olmak üzere performans verilerinin, ürünlerin, web API’lerinin ve bu çağrıları alan işlemlerin bir özeti gösterir.

Belirli bir web API'si veya işlemin bir performans sorununa neden olup olmadığını belirlemek ve gerekirse ana bilgisayar ortamını ölçeklendirip daha fazla sunucu eklemek için bu bilgileri kullanabilirsiniz. Ayrıca bir veya daha fazla uygulamanın orantısız hacimlerde kaynak kullanıp kullanmadığını öğrenebilir ve kota ayarlamak ve çağrı oranlarını sınırlamak üzere uygun ilkeler uygulayabilirsiniz.

Not

Yayımlanmış bir ürünün ayrıntılarını değiştirdiğinizde değişiklikler hemen uygulanır. Örneğin, bir web API’sini içeren ürünü yeniden yayımlamanıza gerek kalmadan web API’sine işlem ekleyebilir ya da kaldırabilirsiniz.

Sonraki adımlar