Webes API implementálása

A gondosan megtervezett RESTful webes API meghatározza az ügyfélalkalmazások számára elérhető erőforrásokat, kapcsolatokat és navigációs sémákat. A webes API-k megvalósításakor és központi telepítésekor a webes API-t futtató környezet fizikai követelményeit és a webes API felépítését kell figyelembe vennie az adatok logikai szerkezete helyett. Ez az útmutató a webes API implementálásának és közzétételének ajánlott eljárásaira összpontosít, hogy elérhetővé tegye az ügyfélalkalmazások számára. A webes API-tervezéssel kapcsolatos részletes információkért tekintse meg a webes API-tervezést.

Kérelmek feldolgozása

A kéréseket kezelő kód megvalósításakor vegye figyelembe az alábbi szempontokat:

A GET, PUT, DELETE, HEAD és JAVÍTÁSI műveleteknek idempotensnek kell lenniük

A kérelmeket megvalósító kódnak nem lehetnek mellékhatásai. Ha egy kérést megismétel ugyanazon az erőforráson, a kérésnek ugyanazt az állapotot kell eredményeznie. Ha például több DELETE-kérést küld ugyanarra az URI-ra, annak ugyanannak a hatásnak kell lennie, bár a válaszüzenetekben szereplő HTTP-állapotkód eltérő lehet. Lehetséges, hogy az első törlési kérelem a 204 (nincs tartalom) állapotkódot, a további törlési kérelmek pedig a 404 (nem található) állapotkódot adják vissza.

Feljegyzés

Jonathan Oliver blogján található idempotenciaminták című cikk áttekintést nyújt az idempotencia és az adatkezelési műveletekhez való viszonyáról.

Az új erőforrásokat létrehozó POST műveleteknek nem lehetnek független mellékhatásai

Ha egy POST-kérelem egy új erőforrás létrehozására szolgál, a kérés hatását az új erőforrásra kell korlátozni (és esetleg bármely közvetlenül kapcsolódó erőforrásra, ha valamilyen kapcsolat áll fenn). Egy e-kereskedelmi rendszerben például az ügyfél számára új rendelést létrehozó POST-kérések is módosíthatják a készletszinteket, és számlázási adatokat hozhatnak létre, de nem módosíthatják a rendeléshez közvetlenül nem kapcsolódó információkat, és nem befolyásolhatják a rendszer általános állapotát.

A POST, PUT és DELETE műveletek ne legyenek hosszadalmasak

A POST, PUT és DELETE kérések támogatása erőforráscsoportokon keresztül. Egy POST kérés tartalmazhatja több új erőforrás részleteit is, amelyeket ugyanahhoz a gyűjteményhez ad hozzá. A PUT kérések egy gyűjtemény teljes erőforráskészletét lecserélhetik, míg a DELETE kérések egy teljes gyűjteményt eltávolíthatnak.

Az ASP.NET Web API 2-ben található OData-támogatás lehetővé teszi a kérések kötegelését. Az ügyfélalkalmazások becsomagolhatnak több webes API-kérést és egyetlen HTTP-kérésben küldhetik el őket a kiszolgálóra, majd egyetlen HTTP-választ kapnak vissza, amely az összes kérésre vonatkozó választ tartalmazza. További információt a Webes API és a Webes API OData kötegelt támogatásának bemutatása című témakörben talál.

Kövesse a HTTP-specifikációkat válasz küldésekor

A webes API-nak olyan üzeneteket kell visszaadnia, amelyek tartalmazzák a megfelelő HTTP-állapotkódot, amelyek alapján az ügyfél el tudja dönteni, hogyan kezelje az eredményt. Emellett tartalmazniuk kell még a megfelelő HTTP-fejléceket, hogy az ügyfél értse az eredmény jellegét, valamint egy megfelelően formázott törzset, amely alapján az ügyfél elemezheti az eredményt.

Például a POST műveletnek a 201 (Létrehozva) állapotkódot kell visszaadnia, a válaszüzenetnek pedig bele kell foglalnia kell az újonnan létrehozott erőforrás URI-jét a válaszüzenet Location fejlécébe.

A tartalomegyeztetés támogatása

A válaszüzenetek törzse többféle formátumú adatokat tartalmazhat. Egy HTTP GET-kérés például JSON- vagy XML-formátumban is visszaadhat adatokat. Az ügyfél által küldött kérés tartalmazhat egy Accept fejlécet, amelyben megadja, hogy milyen adatformátumokat tud kezelni. Ezek a formátumok médiatípusként vannak megadva. Például egy olyan ügyfél, amely get kérelmet ad ki, amely lekéri a képet, megadhat egy Accept fejlécet, amely felsorolja az ügyfél által kezelhető médiatípusokat, például image/jpeg, image/gif, image/png. Amikor a webes API visszaadja az eredményt, az adatokat a felsorolt médiatípusok egyikével kell formáznia, és meg kell adnia a formátumot a válasz Content-Type fejlécében.

Ha az ügyfél nem adott meg Accept fejlécet, akkor az API egy kézenfekvő alapértelmezett formátumot használ a választörzsben. Az ASP.NET webes API-keretrendszer például alapértelmezés szerint a JSON formátumot használja a szöveges adatokhoz.

A HATEOAS módszer lehetővé teszi az ügyfelek számára, hogy egy kezdeti kiindulási pontról navigáljanak és derítsék fel az erőforrásokat. Ez URI-ket tartalmazó hivatkozásokkal történik. Amikor egy ügyfél kiad egy HTTP GET kérést egy erőforrás beszerzéséhez, akkor a válasznak tartalmaznia olyan URI-kat kell tartalmaznia, amelyekkel az ügyfélalkalmazás gyorsan megtalálhat bármilyen közvetlenül kapcsolódó erőforrást. Például vegyünk egy elektronikus kereskedelmi megoldást támogató webes API-t, amelyben egy ügyfél számos megrendelést adott le. Amikor egy ügyfélalkalmazás lekéri az ügyfél adatait, a válasznak olyan hivatkozásokat kell tartalmaznia, amelyek alapján az ügyfélalkalmazás el tudja küldeni a HTTP GET kéréseket a rendelés lekéréséhez. Emellett a kérések végrehajtásához HATEOAS stílusú hivatkozásokkal le kell írnia az egyes hivatkozott erőforrások által támogatott egyéb műveleteket (POST, PUT, DELETE stb.) a megfelelő URI-kkel. Ezt a megközelítést részletesebben az API-tervezésben ismertetjük.

Jelenleg nincsenek a HATEOAS megvalósítására vonatkozó szabványok, de a következő példa bemutat egy lehetséges módszert. Ebben a példában egy HTTP GET kérés, amely megkeresi az ügyfél adatait, egy olyan választ ad vissza, amely hateoAS-hivatkozásokat tartalmaz, amelyek az adott ügyfél megrendelésére hivatkoznak:

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"]}
]}

Ebben a példában a felhasználói adatokat a Customer osztály jelöli a következő kódrészletben. A HATEOAS-hivatkozásokat a Links gyűjteménytulajdonság tartalmazza:

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; }
}

A HTTP GET művelet lekérdezi a felhasználói adatokat a tárolóból, és létrehoz egy Customer objektumot, majd feltölti a Links gyűjteményt. Az eredményt egy JSON-válaszüzenet formájában adja vissza a rendszer. Minden hivatkozás a következő mezőket tartalmazza:

  • A visszaadott objektum és a hivatkozás által leírt objektum közötti kapcsolat (Rel) Ebben az esetben self azt jelzi, hogy a hivatkozás maga az objektumra mutató hivatkozás (hasonló a this sok objektumorientált nyelv mutatóihoz), és orders a kapcsolódó rendelési adatokat tartalmazó gyűjtemény neve.
  • A hivatkozás által leírt objektum hiperhivatkozása (Href) egy URI formájában.
  • Az URI felé küldhető HTTP-kérelem típusa (Action).
  • Azon adatok formátuma (Types), amelyeket meg kell adni a HTTP-kérelemben, vagy amelyeket a válasz visszaadhat, a kérelem típusától függően.

A példa HTTP-válaszban található HATEOAS-hivatkozások azt jelzik, hogy egy ügyfélalkalmazás a következő műveleteket hajthatja végre:

  • Egy HTTP GET kérelem a https://adventure-works.com/customers/2 URI felé, amely (újra) lekéri az ügyfél adatait. Ezek az adatok XML vagy JSON formátumban adhatók vissza.
  • Egy HTTP PUT kérelem a https://adventure-works.com/customers/2 URI felé, amely módosítja az ügyfél adatait. Az új adatokat a kérésüzenetben x-www-form-urlencoded formátumban kell megadni.
  • Egy HTTP DELETE kérelem a https://adventure-works.com/customers/2 URI felé, amely törli az ügyfelet. A kérelem nem vár semmilyen további információt, és nem ad vissza semmilyen adatot a válaszüzenet törzsében.
  • Egy HTTP GET kérelem a https://adventure-works.com/customers/2/orders URI felé, amely lekéri az ügyfél összes rendelését. Ezek az adatok XML vagy JSON formátumban adhatók vissza.
  • HTTP POST-kérés az URI-hoz https://adventure-works.com/customers/2/orders , hogy hozzon létre egy új rendelést az ügyfél számára. Az adatokat a kérésüzenetben x-www-form-urlencoded formátumban kell megadni.

Kivételek kezelése

Ha egy művelet nem kezelt kivételt jelez, vegye figyelembe a következő szempontokat.

Kivételek rögzítése és jelentéssel bíró válasz visszaadása az ügyfeleknek

A HTTP-műveleteket megvalósító kódnak átfogó kivételkezelést kell biztosítania ahelyett, hogy engedné a nem kezelt kivételek propagálását a keretrendszerbe. Ha egy kivétel megakadályozza a művelet sikeres elvégzését, a kivétel visszaadható a válaszüzenetben, de ez esetben jelentéssel bíró leírást is kell adnia a kivételt okozó hibáról. A kivételnek tartalmaznia a megfelelő HTTP-állapotkódot is ahelyett, hogy minden esetben egyszerűen az 500-as állapotkódot adná vissza. Ha például egy felhasználó kérés egy olyan frissítést vált ki, amely megsért egy korlátozást (például megkísérel törölni egy nyitott rendelésekkel rendelkező ügyfelet), akkor a 409 (Ütközés) állapotkódot kell visszaadni, valamint az üzenet törzsében jelezni kell ütközés okát. Ha valamilyen más körülmény akadályozza a kérés teljesítését, akkor a 400 (Hibás kérelem) állapotkód is visszaadható. A HTTP-állapotkódok teljes listáját a W3C webhelyén található Állapotkód-definíciók lapon találja.

A kódpélda rögzíti a különböző körülményeket, és megfelelő választ ad vissza.

[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();
    }
}

Tipp.

Ne tartalmazzon olyan információkat, amelyek hasznosak lehetnek az API-ba behatolni próbáló támadók számára.

Sok webkiszolgáló maga rögzíti a hibák körülményeit, mielőtt a hibák elérnék a webes API-t. Ha például egy webhelyen hitelesítés van konfigurálva, és a felhasználó nem adja meg a megfelelő hitelesítési adatokat, a webkiszolgálónak a 401 (Nem engedélyezett) állapotkódot kell visszaadnia. Az ügyfél hitelesítése után a kód a saját ellenőrzéseivel győződhet meg róla, hogy az ügyfélnek hozzáféréssel kell rendelkeznie a kért erőforráshoz. Ha a hitelesítés sikertelen, a 403 (Tiltott) állapotkódot kell visszaadni.

A kivételek egységes kezelése és a hibákkal kapcsolatos adatok naplózása

A kivételek egységes kezelése érdekében érdemes egy globális hibakezelési stratégiát bevezetnie a teljes webes API-n. Emellett érdemes hibanaplózással rögzítenie az egyes kivételek összes részletét. A hibanapló bármilyen részletes információt tartalmazhat azzal a feltétellel, hogy az ügyfelek a weben keresztül nem férhetnek hozzá.

Az ügyféloldali és kiszolgálóoldali hibák megkülönböztetése

A HTTP-protokoll megkülönbözteti az ügyfélalkalmazás által okozott (HTTP 4xx állapotkódú) és a kiszolgáló hibái miatt előforduló (HTTP 5xx állapotkódú) hibákat. Ügyeljen arra, hogy a hibákkal kapcsolatos válaszüzenetekben betartsa ezt a konvenciót.

Ügyféloldali adatelérés optimalizálása

Az elosztott környezetekben, például amelyekben egy webkiszolgáló és ügyfélalkalmazások találhatók, az egyik elsődleges hibaforrás a hálózat. Ez jelentős szűk keresztmetszeteket okozhat, különösen akkor, ha egy ügyfélalkalmazás gyakran küld kérelmeket vagy fogad adatokat. Ezért törekedni kell a hálózaton keresztül zajló forgalom minimalizálására. Az adatok lekérését és karbantartását kezelő kód megvalósításakor vegye figyelembe az alábbi szempontokat:

Az ügyféloldali gyorsítótárazás támogatása

A HTTP 1.1 protokoll támogatja a gyorsítótárazást az ügyfeleken és köztes kiszolgálókon, amelyeken egy Cache-Control fejléc irányítja a kérelmeket. Amikor egy ügyfélalkalmazás egy HTTP GET kérést küld a webes API-nak, a válasz tartalmazhat egy Cache-Control fejlécet, amely jelzi, hogy a válasz törzsében található adatok biztonságosan gyorsítótárazhatók-e az ügyfélnél vagy egy köztes kiszolgálón, amelyen a kérelem áthaladt, valamint megadja, hogy az adatok mennyi idő után járnak le és válnak elavulttá.

A következő példa bemutat egy HTTP GET kérelmet és a rá adott választ, amely tartalmaz egy Cache-Control fejlécet:

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}

Ebben a példában a Cache-Control fejléc megadja, hogy a visszaadott adatok 600 másodperc után járnak le, csak egyetlen ügyfél számára megfelelők és tilos őket más ügyfelek által is használt megosztott gyorsítótárakban tárolni (vagyis private (bizalmas) adatokról van szó). A Cache-Control fejléc a private helyett megadhat public (nyilvános) beállítást is, amely esetben az adatok tárolhatók egy megosztott gyorsítótárban, vagy megadhatja a no-store (nincs tárolás) értéket, amely esetben az adatok nem gyorsítótárazhatók az ügyfélben. Az alábbi példakód bemutatja, hogyan hozható létre egy Cache-Control fejléc a válaszüzenetben:

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;
    }
    ...
}

Ez a kód egy egyéni IHttpActionResult osztályt használ.OkResultWithCaching Ez az osztály lehetővé teszi a vezérlőnek a gyorsítótárfejléc tartalmának beállítását:

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;
    }
}

Feljegyzés

A HTTP-protokoll a no-cache direktívát is meghatározza a Cache-Control fejléchez. Megtévesztő módon ez nem azt jelenti, hogy az adatokat nem lehet gyorsítótárazni, hanem hogy a gyorsítótárazott adatokat ellenőriztetni kell a kiszolgálóval a visszaadás előtt – tehát az adatok gyorsítótárazhatók, de minden használatkor ellenőrizni kell, hogy még aktuálisak-e.

A gyorsítótár kezelése az ügyfélalkalmazás vagy a köztes kiszolgáló feladata, de ha megfelelően van megvalósítva, akkor a használatával sávszélesség takarítható meg és növelhető a teljesítmény, mivel nincs szükség a már beszerzett adatok újbóli lekérésére.

A Cache-Control fejléc max-age (maximális kor) értéke csak tájékoztató jellegű, és nem garantálja, hogy a vonatkozó adatok időközben nem változnak. A webes API-nak úgy kell beállítania a max-age értékét, hogy tükrözze az adatok várható érvényességét. Ha ez az időszak lejár, az ügyfélnek törölnie kell az objektumot a gyorsítótárból.

Feljegyzés

A legtöbb modern böngésző támogatja az ügyféloldali gyorsítótárazást azáltal, hogy az ismertetett módon gyorsítótár-vezérlő fejléceket ad hozzá a kérelmekhez, és megvizsgálja az eredmények fejlécét. Egyes régebbi böngészők azonban nem gyorsítótárazzák az olyan URL-címekről visszakapott adatokat, amelyek lekérdezési sztringet tartalmaznak. Ez általában nem okoz problémát az olyan egyéni ügyfélalkalmazások számára, amelyek az itt tárgyalt protokollon alapuló saját gyorsítótár-kezelési stratégiával rendelkeznek.

Egyes régebbi proxyk ugyanígy viselkednek, és lehetséges, hogy nem gyorsítótárazzák a lekérdezési sztringekat tartalmazó URL-címeken alapuló kérelmeket. Ez az olyan egyedi ügyfélalkalmazások számára jelenthet problémát, amelyek egy ilyen proxyn keresztül csatlakoznak egy webkiszolgálóhoz.

A lekérdezés feldolgozásának optimalizálása ETagek megadásával

Amikor egy ügyfélalkalmazás lekér egy objektumot, a válaszüzenet egy ETaget (entitáscímkét) is tartalmazhat. Az ETag egy átlátszatlan sztring, amely egy erőforrás verzióját jelzi; minden alkalommal, amikor egy erőforrás módosítja az ETaget is. Az ügyfélalkalmazásnak az adatokkal együtt az ETaget is gyorsítótáraznia kell. Az alábbi példakód bemutatja, hogyan lehet hozzáadni egy ETaget egy HTTP GET kérelemre adott válaszhoz. Ez a kód a GetHashCode metódussal létrehoz egy numerikus értéket, amely azonosítja az objektumot (ha szükséges, felülírhatja ezt a metódust, és létrehozhat egy saját kivonatot az MD5 vagy más algoritmus segítségével):

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;
    }
    ...
}

A webes API által közzétett válaszüzenet így néz ki:

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}

Tipp.

Biztonsági okokból ne engedélyezze a hitelesített (HTTPS) kapcsolaton keresztül visszaadott bizalmas adatok vagy adatok gyorsítótárazásához.

Egy ügyfélalkalmazás egy újabb GET kéréssel bármikor újra lekérheti ugyanazt az erőforrást, és ha az erőforrás változott (ha más az ETagje), akkor a gyorsítótárazott verziót el kell távolítani, és az új verziót kell hozzáadni a gyorsítótárhoz. Ha egy erőforrás nagy méretű, és az ügyfélnek való visszaküldése jelentős sávszélességet igényel, akkor nem hatékony több kérelmet küldeni ugyanannak az adatnak a lekérése céljából. A HTTP-protokoll ennek elkerülése érdekében a következő folyamatot határozza meg a GET kérelmek optimalizálásához, amelyet a webes API-knak támogatniuk kell:

  • Az ügyfél létrehoz egy GET kérelmet, amely az erőforrás jelenleg gyorsítótárazott verziójának ETagjét tartalmazza, és egy If-None-Match HTTP-fejlécben hivatkozik rá:

    GET https://adventure-works.com/orders/2 HTTP/1.1
    If-None-Match: "2147483648"
    
  • A webes API GET művelete lekéri a kért adatok jelenlegi ETag címkéjét (2. rendelés a fenti példában), és összehasonlítja az értéket az If-None-Match fejlécben találhatóval.

  • Ha a kért adatok jelenlegi ETagje megegyezik a kérés által megadott ETaggel, akkor az erőforrás nem változott, és a webes API-nak a HTTP-válaszban egy üres üzenettörzset és a 304 (Nem módosított) állapotkódot kell visszaadnia.

  • Ha a kért adatok jelenlegi ETagje nem egyezik a kérés által megadott ETaggel, akkor az adatok változtak, és a webes API-nak a HTTP-válaszban az üzenettörzsben meg kell adnia az új adatokat és a 200 (OK) állapotkódot.

  • Ha a kért adatok már nem léteznek, akkor a webes API-nak egy 404 (Nem található) állapotkódú HTTP-választ kell visszaadnia.

  • Az ügyfél az állapotkódot használja a gyorsítótár karbantartásához. Ha az adatok nem változtak (304-es állapotkód), akkor az objektum a gyorsítótárban maradhat, és ügyfélalkalmazás tovább használhatja az objektum jelenlegi verzióját. Ha az adatok megváltoztak (200-as állapotkód), akkor a gyorsítótárazott objektumot el kell távolítani, és egy újat kell beszúrni helyette. Ha az adatok már nem érhetők el (404-es állapotkód), akkor az objektumot el kell távolítani a gyorsítótárból.

Feljegyzés

Ha a válasz fejléce a no-store Cache-Control fejlécet tartalmazza, akkor az objektumot mindenképp el kell távolítani a gyorsítótárból, a HTTP-állapotkódtól függetlenül.

Az alábbi kód az FindOrderByID If-None-Match fejléc támogatásához kiterjesztett metódust mutatja be. Figyelje meg, hogy ha az If-None-Match fejléc hiányzik, a rendszer mindig lekéri a megadott rendelést:

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();
        }
    }
...
}

Ebben a példában egy EmptyResultWithCaching nevű másik egyéni IHttpActionResult osztály is található. Ez az osztály egyszerű csomagolásként szolgál egy HttpResponseMessage objektum körül, amely nem tartalmaz választörzset:

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;
    }
}

Tipp.

Ebben a példában az adatok ETagje az alapul szolgáló adatforrásból lekért adatok kivonatolásával jön létre. Ha az ETag más módon is kiszámítható, akkor a folyamat tovább optimalizálható, és az adatokat csak akkor kell lekérni az adatforrásból, ha változtak. Ez a módszer különösen hasznos, ha az adatok mérete nagy, vagy az adatforrás elérése jelentős késést eredményezhet (például ha az adatforrás egy távoli adatbázis).

Optimista párhuzamosság támogatása ETagek használatával

A korábban gyorsítótárazott adatok frissítésének engedélyezéséhez a HTTP-protokoll támogat egy optimista párhuzamossági stratégiát. Ha egy erőforrás lekérése és gyorsítótárazása után az ügyfélalkalmazás később PUT vagy DELETE kérést küld az erőforrás módosítására vagy eltávolítására, tartalmaznia kell egy If-Match fejlécet, amely az ETagre hivatkozik. A webes API ezen információk alapján határozza meg, hogy az erőforrást a lekérése óta módosította-e egy másik felhasználó, majd az alábbiak szerint visszaküldi a megfelelő választ az ügyfélalkalmazásnak:

  • Az ügyfél létrehoz egy PUT kérelmet, amely tartalmazza az erőforrás új adatait és az erőforrás jelenleg gyorsítótárazott verziójának ETagjét, amelyre egy If-Match HTTP-fejléc hivatkozik. A következő példa egy rendelést frissítő PUT kérelmet mutat be:

    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
    
  • A webes API PUT művelete lekéri a kért adatok jelenlegi ETag címkéjét (1. rendelés a fenti példában), és összehasonlítja az értéket az If-Match fejlécben találhatóval.

  • Ha a kért adatok jelenlegi ETagje megegyezik a kérés által megadott ETaggel, akkor az erőforrás nem változott, és a webes API-nak el kell végeznie a frissítést, majd a sikeres frissítés után egy 204 (Nem módosított) HTTP-állapotkódú üzenetet kell visszaadnia. A válasz tartalmazhatja az erőforrás frissített verziójának Cache-Control és ETag fejléceit. A válasznak mindig tartalmaznia kell a Location fejlécet, amely az újonnan frissített erőforrás URI-jére hivatkozik.

  • Ha a kért adatok jelenlegi ETagje nem egyezik a kérés által megadott ETaggel, akkor a lekérés óta egy másik felhasználó módosította az adatokat, a webes API-nak pedig a HTTP-válaszban egy üres üzenettörzset és a 412 (Nem teljesül az előfeltétel) állapotkódot kell visszaadnia.

  • Ha a frissítendő erőforrás már nem létezik, akkor a webes API-nak egy 404 (Nem található) állapotkódú HTTP-választ kell visszaadnia.

  • Az ügyfél az állapotkóddal és a válaszfejlécekkel tartja karban a gyorsítótárat. Ha az adatok frissültek (204-es állapotkód), akkor az objektum maradhat a gyorsítótárban (amennyiben a Cache-Control fejléc nem a no-store értéket tartalmazza), de az ETaget frissíteni kell. Ha az adatokat egy másik felhasználó módosította (állapotkód: 412), vagy nem található (állapotkód: 404), akkor a gyorsítótárazott objektumot el kell vetni.

A következő példakód az Orders vezérlő PUT műveletének megvalósítását mutatja be:

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();
        }
    }
    ...
}

Tipp.

Az If-Match fejléc használata teljesen választható, és ha elhagyja, a webes API mindig megpróbálja frissíteni a megadott rendelést, akár vakon felülírva egy másik felhasználó által végrehajtott frissítést. Az elveszett frissítések miatti problémák elkerüléséhez mindig adjon meg egy If-Match fejlécet.

Nagyméretű kérelmek és válaszok kezelése

Előfordulhat, hogy egy ügyfélalkalmazásnak olyan kéréseket kell kiadnia, amelyek több megabájtos (vagy nagyobb) méretű adatokat küldenek vagy fogadnak. Ha az ügyfélalkalmazás ekkora mennyiségű adat átvitelére várakozik, előfordulhat, hogy nem válaszol. Ha jelentős mennyiségű adatot tartalmazó kérelmeket kezel, vegye figyelembe a következő szempontokat:

Nagyméretű objektumokat tartalmazó kérelmek és válaszok optimalizálása

Egyes erőforrások lehetnek nagy objektumok, vagy nagy mezők, például grafikus képek vagy más típusú bináris adatok. A webes API-nak támogatnia kell a streamelést az ilyen erőforrások fel- és letöltésének optimalizálásához.

A HTTP-protokoll biztosítja a darabolásos átvitel kódolási mechanizmusát, amellyel a nagyméretű adatobjektumok visszastreamelhetők egy ügyfélhez. Amikor az ügyfél elküld egy nagy objektumra vonatkozó HTTP GET kérést, a webes API képes a választ darabonkénti adattömbök formájában visszaküldeni egy HTTP-kapcsolaton keresztül. Előfordulhat, hogy a válaszban szereplő adatok hossza kezdetben nem ismert (előfordulhat, hogy létrejön), ezért a webes API-t üzemeltető kiszolgálónak minden egyes adattömbtel egy válaszüzenetet kell küldenie, amely a Fejlécet adja meg a Transfer-Encoding: Chunked Tartalomhossz fejléc helyett. Az ügyfélalkalmazás egymás után kaphatja meg az egyes adattömböket, amelyekből felépíti a teljes választ. Az adatok átvitele akkor ér véget, amikor a kiszolgáló visszaküld egy nulla méretű végső tömböt.

Egyetlen kérelem is eredményezhet egy olyan nagyméretű objektumot, amely jelentős erőforrásokat használ fel. Ha a streamelési folyamat során a webes API megállapítja, hogy a kérelemben szereplő adatok mennyisége túllépett néhány elfogadható korlátot, megszakíthatja a műveletet, és egy 413-es állapotkódú válaszüzenetet küld (túl nagy kérelem entitás).

A hálózaton keresztül továbbított nagyméretű objektumok mérete HTTP-tömörítéssel minimalizálható. Ez a módszer segít csökkenteni a hálózati forgalmat és a kapcsolódó hálózati késést, viszont az ügyfélnek és a webes API-t futtató kiszolgálónak egyaránt további feldolgozást kell végeznie. Például egy olyan ügyfélalkalmazás, amely tömörített adatokat vár, tartalmazhat egy Accept-Encoding: gzip kérésfejlécet (más adattömörítési algoritmusok is megadhatóak). Ha a kiszolgáló támogatja a tömörítést, az üzenet törzsében gzip formátumban tárolt tartalommal és a Content-Encoding: gzip válaszfejlécmel kell válaszolnia.

A tömörítés kombinálható a streameléssel: a streamelés előtt tömörítse az adatokat, és adja meg a gzip tartalomkódolást és a darabolt átviteli kódolást az üzenetfejlécekben. Vegye figyelembe, hogy egyes webkiszolgálók (például az Internet Information Server) beállíthatók úgy, hogy automatikusan tömörítsék a HTTP-válaszokat, függetlenül attól, hogy a webes API tömöríti-e az adatokat.

Részleges válaszok implementálása olyan ügyfelek esetében, amelyek nem támogatják az aszinkron műveleteket

Az aszinkron streamelés alternatívájaként az ügyfélalkalmazás explicit módon megadhatja, hogy a nagy objektumok esetében tömbökben kéri az adatokat. Ezeket a tömböket részleges válaszoknak hívják. Az ügyfélalkalmazás egy HTTP HEAD kérést küld az objektum adatainak lekéréséhez. Ha a webes API támogatja a részleges válaszokat, válaszüzenettel kell válaszolnia a HEAD-kérésre, amely egy fejlécet és egy Content-Length fejlécet tartalmazAccept-Ranges, amely az objektum teljes méretét jelzi, de az üzenet törzsének üresnek kell lennie. Az ügyfélalkalmazás ezen információk alapján hoz létre több GET kérést, amelyekben megadja a fogadni kívánt bájttartományt. A webes API-nak egy 206-os HTTP-állapotú (részleges tartalom), egy tartalomhosszúságú fejlécet kell visszaadnia, amely megadja a válaszüzenet törzsében szereplő adatok tényleges mennyiségét, valamint egy Tartalomtartomány fejlécet, amely jelzi az adat által képviselt objektum melyik részét (például bájtról bájtra 40008000).

A HTTP HEAD-kérelmeket és a részleges válaszokat az API-tervezés részletesebben ismerteti.

Kerülje a szükségtelen 100-Continue állapotüzenetek küldését az ügyfélalkalmazásban

Ha egy ügyfélalkalmazás nagy mennyiségű adatot készül küldeni egy kiszolgálóra, akkor először megállapíthatja, hogy a kiszolgáló egyáltalán hajlandó-e fogadni a kérést. Az adatküldés előtt az ügyfélalkalmazás elküldhet egy HTTP-kérelmet, amely tartalmazza az „Expect: 100-Continue” fejlécet és az adatok méretét jelző Content-Length fejlécet, de az üzenettörzse üres. Ha a kiszolgáló hajlandó kezelni a kérést, akkor a válaszüzenetében a 100 (Folytatás) HTTP-állapotkódot kell megadnia. Az ügyfélalkalmazás ezután elküldheti a teljes kérést, az üzenet törzsében megadott adatokkal.

Ha IIS használatával üzemeltet egy szolgáltatást, a HTTP.sys illesztőprogram automatikusan észleli és kezeli a Várt: 100-Folytatás fejléceket, mielőtt kéréseket ad át a webalkalmazásnak. Ez azt jelenti, hogy az alkalmazás kódjában valószínűleg nem lesznek láthatók ezek a fejlécek, és feltételezhető, hogy az IIS már kiszűrte az olyan üzeneteket, amelyeket nem megfelelőnek vagy túl nagynak talált.

Ha ügyfélalkalmazásokat hoz létre a .NET-keretrendszer használatával, akkor az összes POST és PUT üzenet először a Várt: 100-Folytatás fejlécekkel küld üzeneteket alapértelmezés szerint. A kiszolgálóoldalhoz hasonlóan a .NET-keretrendszer transzparens módon kezeli a folyamatot. Ez a folyamat azonban azzal jár, hogy minden POST és PUT kérés teljesítése két üzenetváltást igényel a kiszolgálóval, még a kis méretű kérések is. Ha az alkalmazás nem küld nagy mennyiségű adatot tartalmazó kérelmeket, akkor letilthatja ezt a funkciót, ha a ServicePointManager osztállyal hoz létre ServicePoint objektumokat az ügyfélalkalmazásban. A ServicePoint objektum a kiszolgálón lévő erőforrásokat azonosító URI-k séma- és gazdagéptöredékei alapján kezeli az ügyfél által a kiszolgálóval létrehozott kapcsolatokat. Ezután a ServicePoint objektum Expect100Continue tulajdonságát false (hamis) értékre állíthatja. Minden későbbi POST és PUT kérés, amelyet az ügyfél a ServicePoint objektum séma- és gazdagéptöredékeivel megegyező URI-n keresztül küld, „Expect: 100-Continue” fejlécek nélkül lesz elküldve. A következő kód bemutatja, hogyan konfigurálható egy ServicePoint objektum, amely az URI-knek küldött összes kérést http sémával és www.contoso.com gazdagéppel konfigurálja.

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

Az osztály statikus Expect100Continue tulajdonságát úgy is beállíthatja ServicePointManager , hogy a tulajdonság alapértelmezett értékét adja meg az összes később létrehozott ServicePoint-objektumhoz .

Tördelés támogatása olyan kéréseknél, amelyek esetlegesen nagy számú objektumot adhatnak vissza

Ha egy gyűjtemény sok erőforrást tartalmaz, egy GET kérés eljuttatása a megfelelő URI-hez jelentős mértékű feldolgozást igényelhet a webes API-t üzemeltető kiszolgálón, ami hatással lehet a teljesítményre és nagy mennyiségű hálózati forgalommal járhat, ez pedig a késések növekedéséhez vezet.

Az ilyen esetek kezeléséhez a webes API-nak támogatnia kell az olyan lekérdezési sztringekat, amelyek lehetővé teszik, hogy az ügyfélalkalmazás pontosítsa a kérelmeket, vagy könnyebben kezelhető, különálló blokkokra (vagy lapokra) tagolva kérje le az adatokat. Az alábbi kód a GetAllOrders vezérlő metódusát Orders mutatja be. Ez a metódus a rendelések részleteit kéri le. Ha a metódus korlátozás nélküli lenne, előfordulhat, hogy nagy mennyiségű adatot adna vissza. A limit és az offset paraméter célja, hogy az adatok mennyiségét egy kisebb részhalmazra csökkentse, ebben az esetben alapértelmezés szerint csak az első 10 rendelésre:

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;
    }
    ...
}

Egy ügyfélalkalmazás kiadhat olyan kérelmet, amely 30 rendelést kér le 50-es eltolástól kezdve a https://www.adventure-works.com/api/orders?limit=30&offset=50 URI használatával.

Tipp.

Ne engedélyezze az ügyfélalkalmazásoknak olyan lekérdezési sztringek megadását, amelyek 2000 karakternél hosszabb URI-t eredményeznek. Sok webes ügyfél és kiszolgáló nem tudja kezelni az ilyen hosszú URI-kat.

A válaszképesség, a skálázhatóság és a rendelkezésre állás fenntartása

Ugyanezt a webes API-t számos, a világ bármely pontján futó ügyfélalkalmazás használhatja. Fontos, hogy a webes API úgy legyen megvalósítva, hogy válaszképes legyen nagy mértékű terhelés alatt is, hogy skálázható legyen a nagymértékben ingadozó számítási feladatok kezeléséhez, és hogy garantáltan rendelkezésre álljon az üzleti szempontból kulcsfontosságú műveleteket végző ügyfelek számára. Mindezen követelmények teljesítése érdekében vegye figyelembe a következő szempontokat:

A hosszan futó kérelmek aszinkron támogatásának biztosítása

Az olyan kérelmeket, amelyek feldolgozása hosszú időbe telhet, a kérelmet küldő ügyfél blokkolása nélkül kell feldolgozni. A webes API elvégezhet néhány kezdeti ellenőrzést a kérelem érvényesítéséhez, elindíthat egy külön feladatot a munka elvégzéséhez, majd visszaadhat egy 202 (Elfogadva) HTTP-kódú válaszüzenetet. A feladat futhat aszinkron módon a webes API feldolgozófolyamatának részeként, vagy kiszervezhető egy háttérfeladatba.

A webes API-nak emellett biztosítania kell egy mechanizmust, amely visszaadja a feldolgozás eredményét az ügyfélalkalmazásnak. Ennek érdekében megadhat az ügyfélalkalmazásoknak egy lekérdezési mechanizmust, amellyel időnként lekérdezhetik, hogy a feldolgozás befejeződött-e, és lekérhetik az eredményt, vagy engedélyezhetjük, hogy a webes API egy értesítést küldjön a művelet befejezése után.

Egyszerűen megvalósíthat egy lekérdezési mechanizmust, ha a következőképpen megad egy virtuális erőforrásként szolgáló lekérdezési URI-t:

  1. Az ügyfélalkalmazás elküldi a kezdeti kérelmet a webes API-nak.
  2. A webes API az Azure Table Storage-ban vagy a Microsoft Azure Cache-ben tárolt táblában tárolja a kéréssel kapcsolatos információkat, és létrehoz egy egyedi kulcsot ehhez a bejegyzéshez, esetleg GUID formátumban. Másik lehetőségként egy, a kéréssel és az egyedi kulccsal kapcsolatos információkat tartalmazó üzenet is elküldhető az Azure Service Buson keresztül.
  3. A webes API a feldolgozást külön feladatként vagy egy olyan tárral kezdeményezi, mint a Hangfire. A webes API a táblában a feladat állapotát Fut értékre állítja.
    • Az Azure Service Bus használata esetén az üzenetfeldolgozás az API-tól elkülönítve, esetleg az Azure Functions vagy az AKS használatával történik.
  4. A webes API egy 202-es (elfogadott) HTTP-állapotkódú válaszüzenetet és egy URI-t ad vissza, amely tartalmazza a létrehozott egyedi kulcsot – például a /polling/{guid}.
  5. Amikor a feladat befejeződött, a webes API az eredményeket a táblában tárolja, és a tevékenység állapotát befejezettre állítja. Vegye figyelembe, hogy ha a feladat meghiúsul, a webes API a sikertelenségről is tárolhat információkat, az állapotot pedig Sikertelen értékre állíthatja.
    • Érdemes újrapróbálkozási technikákat alkalmazni az esetleges átmeneti hibák megoldásához.
  6. A feladat futása közben az ügyfél továbbra is végezhet saját feldolgozást. Rendszeresen küldhet kérést a korábban kapott URI-nak.
  7. Az URI webes API lekérdezi a tábla megfelelő feladatának állapotát, és egy 200-es (OK) HTTP-állapotkódot tartalmazó válaszüzenetet ad vissza, amely tartalmazza ezt az állapotot (Futtatás, Befejezett vagy Sikertelen). Ha a feladat befejeződött vagy meghiúsult, a válaszüzenet tartalmazhatja a feldolgozás eredményét vagy a sikertelenség okával kapcsolatban elérhető információkat is.
    • Ha a hosszú ideig futó folyamat köztesebb állapotokkal rendelkezik, jobb, ha olyan kódtárat használ, amely támogatja a sagamintát, például az NServiceBust vagy a MassTransitet.

Az értesítések megvalósításának lehetőségei a következők:

  • Értesítési központ használata aszinkron válaszok leküldéséhez az ügyfélalkalmazásokhoz. További információ: Értesítések küldése adott felhasználóknak az Azure Notification Hubs használatával.
  • A Comet modell használata egy állandó hálózati kapcsolat fenntartásához az ügyfél és a webes API-t üzemeltető kiszolgáló között, és a kapcsolat használata a kiszolgálóról az ügyfélhez visszaküldött üzenetek leküldéséhez. Ehhez az MSDN magazin Egyszerű Comet-alkalmazás Microsoft .NET-keretrendszerben való létrehozását ismertető cikkében talál egy példát.
  • A SignalR használatával valós időben küldhet le adatokat a webkiszolgálóról az ügyfélre egy állandó hálózati kapcsolaton keresztül. A SignalR az ASP.NET-webalkalmazásokhoz NuGet-csomagként érhető el. További információt az ASP.NET SignalR webhelyen talál.

Az egyes kérelmek állapotnélküliségének biztosítása

Minden egyes kérelmet atominak kell tekinteni. Egy ügyfélalkalmazás különböző időpontokban elküldött kérelmei között nem állhatnak fenn függőségek. Ez a módszer segíti a méretezhetőséget, és a webszolgáltatás példányai több kiszolgálóra is telepíthetők. Az ügyfélkérések bármelyik példányhoz irányíthatók, és az eredmények mindig azonosak. A megoldás hasonlóképpen javítja a rendelkezésre állást is: ha egy webkiszolgáló meghibásodik, a kérések átirányíthatók egy másik példányhoz az Azure Traffic Managerrel, amíg a kiszolgáló újraindul, és mindez semmilyen negatív hatással nincs az ügyfélalkalmazásra.

Ügyfelek nyomon követése és szabályozás implementálása a DoS-támadások esélyének csökkentése érdekében

Ha egy adott ügyfél nagy számú kérést küld egy adott időn belül, előfordulhat, hogy kisajátítja a szolgáltatást, és befolyásolja a további ügyfelek teljesítményét. Ennek elkerülése érdekében a webes API monitorozhatja az ügyfélalkalmazások hívásait. Ez az összes bejövő kérelem IP-címének rögzítésével vagy az összes hitelesített hozzáférés naplózásával is történhet. Ezen adatok alapján korlátozható az erőforrásokhoz való hozzáférés. Ha egy ügyfél túllép egy adott korlátozását, a webes API visszaadhat egy válaszüzenetet az 503 (A szolgáltatás nem érhető el) állapotkóddal és egy Retry-After fejléccel, amelyben megadja, hogy az ügyfél mikor küldheti el a következő kérelmet anélkül, hogy a rendszer elutasítaná. Ez a stratégia segíthet csökkenteni a szolgáltatásmegtagadási (DoS-) támadások esélyét a rendszert elakadó ügyfelek egy csoportjából.

Állandó HTTP-kapcsolatok gondos kezelése

A HTTP-protokoll támogatja az állandó HTTP-kapcsolatokat, ahol elérhetők. A HTTP 1.0 specifikáció hozzáadta a Csatlakozás ion:Keep-Alive fejlécet, amely lehetővé teszi, hogy az ügyfélalkalmazás jelezze a kiszolgálónak, hogy ugyanazt a kapcsolatot használhatja a következő kérések küldésére az újak megnyitása helyett. A kapcsolat automatikusan lezárul, ha az ügyfél nem használja újra egy bizonyos időtartamon belül, amelyet a gazdagép határoz meg. Ez az Azure-szolgáltatások által használt HTTP 1.1 alapértelmezett viselkedése, így az üzenetekbe nem szükséges Keep-Alive fejléceket belefoglalni.

A kapcsolat nyitva tartása segíthet növelni a válaszkészséget a késés és a hálózati torlódás csökkentésével, de gyengítheti a skálázhatóságot, mivel a szükségtelen kapcsolatok felesleges nyitva tartása korlátozza a további ügyfelek csatlakozási lehetőségeit. Emellett ha az ügyfélalkalmazás mobileszközön fut, csökkentheti az eszköz akkumulátor-élettartamát is: ha az alkalmazás csak alkalmanként kérelmeket küld a kiszolgáló felé, a kapcsolat nyitva tartása gyorsabban lemerítheti az akkumulátort. Annak biztosításához, hogy a HTTP 1.1 ne tegyen állandóvá egy kapcsolatot, az ügyfél egy Connection:Close fejléc használatával felülírhatja az alapértelmezett viselkedést. Ha egy kiszolgáló rendkívül nagy mennyiségű ügyfelet kezel, akkor a válaszaiban a Connection:Close fejléc használatával hasonló módon lezárhatja a kapcsolatokat, így kiszolgáló-erőforrásokat takaríthat meg.

Feljegyzés

Az állandó HTTP-kapcsolatok funkciója teljes mértékben választható, és arra szolgál, hogy csökkentse a kommunikációs csatornák ismétlődő létrehozásával járó hálózati terhelést. Sem a webes API, sem az ügyfélalkalmazás nem függhet egy állandó HTTP-kapcsolat elérhetőségétől. Ne használjon állandó HTTP-kapcsolatokat üstökös típusú értesítési rendszerek implementálásához; ehelyett a TCP-rétegben használjon szoftvercsatornákat (vagy ha elérhető webes szoftvercsatornákat). Végül vegye figyelembe, hogy a Keep-Alive fejlécek csak korlátozottan használhatók, ha az ügyfélalkalmazás egy proxyn keresztül kommunikál a kiszolgálóval: ez esetben csak az ügyfél és a proxy kapcsolata lesz állandó.

Webes API-k közzététele és kezelése

Ahhoz, hogy egy webes API elérhető legyen az ügyfélalkalmazások számára, a webes API-t telepíteni kell egy gazdakörnyezetben. Ez a környezet általában egy webkiszolgáló, bár valamilyen más típusú gazdafolyamat is lehet. A webes API-k közzétételekor vegye figyelembe a következő szempontokat:

  • Minden kérelmet hitelesíteni és engedélyezni kell, és be kell tartatni a megfelelő szintű hozzáférés-vezérlést.
  • A kereskedelmi webes API-k válaszidejére különböző minőségi garanciák vonatkozhatnak. Fontos gondoskodni arról, hogy a gazdagépkörnyezet méretezhető legyen, ha a terhelés idővel jelentősen változhat.
  • Szükség lehet a kérelmek mérésére pénzügyi okokból.
  • Lehetséges, hogy a webes API felé irányuló forgalmat korlátozni kell, valamint a kvótájukat felhasználó adott ügyfelekre vonatkozó szabályozást kell bevezetni.
  • A szabályozási követelmények előírhatják az összes kérelem és válasz naplózását.
  • A rendelkezésre állás biztosítása érdekében szükség lehet a webes API-t futtató kiszolgáló állapotának monitorozására, és adott esetben újraindítására.

Hasznos lehet ezeket a problémákat elkülöníteni a webes API megvalósításával kapcsolatos technikai problémáktól. Emiatt érdemes lehet létrehozni egy előtérrendszert, amely külön folyamatként fut, és a webes API-hoz irányítja a kérelmeket. Az előtérrendszer felügyeleti műveleteket biztosíthat, és továbbíthatja az érvényesített kéréseket a webes API felé. Az előtérrendszer használata számos funkcionális előnnyel is jár, többek között:

  • Több webes API integrációs pontjaként szolgál.
  • különböző technológiák használatával átalakítja az üzeneteket és lefordítja a kommunikációs protokollokat az ügyfelek számára.
  • Gyorsítótárazza a kérelmeket és válaszokat a webes API-t futtató kiszolgáló terhelésének csökkentése érdekében.

Webes API tesztelése

A webes API-kat ugyanolyan alaposan kell tesztelni, mint minden más szoftvert. Érdemes lehet egységteszteket létrehozni a funkció ellenőrzéséhez.

A webes API természete további követelményeket támaszt annak ellenőrzéséhez, hogy megfelelően működik-e. Fordítson különös figyelmet a következőkre:

  • Ellenőrizze az összes útvonalat, hogy a megfelelő műveleteket hívják-e meg. Különösen figyeljen a váratlanul visszaadott 405 (Nem engedélyezett metódus) HTTP-állapotkódra, mivel ez azt jelezheti, hogy egy útvonal és a rajta keresztül elküldhető HTTP-metódusok (GET, POST, PUT, DELETE) nem egyeznek.

    HTTP-kérések küldése olyan útvonalakra, amelyek nem támogatják őket, például POST-kérés küldése egy adott erőforrásnak (a POST-kéréseket csak erőforráscsoportoknak kell elküldeni). Ezekben az esetekben az egyetlen érvényes válasz a 405 (Nem engedélyezett) állapotkód lehet.

  • Ellenőrizze, hogy az összes útvonal megfelelően védett-e, és megtörténnek-e a megfelelő hitelesítési és engedélyezési ellenőrzések.

    Feljegyzés

    Bizonyos biztonsági intézkedésekért, például a felhasználók hitelesítésért valószínűleg nem a webes API, hanem a gazdakörnyezet felel, de ettől függetlenül még szükséges a biztonsági vizsgálatok elvégzése a telepítési folyamat részeként.

  • Tesztelje az egyes műveletek kivételkezelését, és ellenőrizze, hogy a műveletek megfelelő és jelentéssel bíró HTTP-válaszokat adnak-e vissza az ügyfélalkalmazásnak.

  • Ellenőrizze, hogy a kérelem- és válaszüzenetek szabályosak-e. Ha például egy HTTP POST kérelem x-www-form-urlencoded formátumban tartalmazza egy új erőforrás adatait, győződjön meg arról, hogy a vonatkozó művelet megfelelően elemzi az adatokat, létrehozza az erőforrásokat, és visszaad egy választ, amely tartalmazza az új erőforrás részleteit, köztük a megfelelő Location fejlécet.

  • Ellenőrizze az összes hivatkozást és URI-t a válaszüzenetekben. Egy HTTP POST-üzenetnek például az újonnan létrehozott erőforrás URI-ját kell visszaadnia. Minden HATEOAS-hivatkozásnak érvényesnek kell lennie.

  • Győződjön meg arról, hogy a minden művelet a megfelelő állapotkódokat adja vissza a különböző bemeneti kombinációkra. Példa:

    • Ha egy lekérdezés sikeres, a 200 (OK) állapotkódot kell visszaadnia.
    • Ha egy erőforrás nem található, a műveletnek a 404 (Nem található) HTTP-állapotkódot kell visszaadnia.
    • Ha az ügyfél elküld egy kérelmet, amely sikeresen töröl egy erőforrást, a 204 (Nincs tartalom) állapotkódnak kell megjelennie.
    • Ha az ügyfél egy új erőforrást létrehozó kérést küld, az állapotkódnak 201 (Létrehozva) kell lennie.

Figyeljen a válaszokban a váratlan állapotkódokra az 5xx tartományban. Ezekkel az üzenetekkel a gazdakiszolgáló általában azt jelzi, hogy nem tudott teljesíteni egy érvényes kérelmet.

  • Tesztelje az ügyfélalkalmazás által megadható különböző fejléc-kombinációkat, és győződjön meg arról, hogy a webes API a várt információt adja vissza a válaszüzenetekben.

  • Tesztelje a lekérdezési sztringekat. Ha egy műveletnek választható paraméterei is lehetnek (például tördelési kérések), tesztelje a paraméterek különböző kombinációit és sorrendjeit.

  • Ellenőrizze, hogy az aszinkron műveletek sikeresen befejeződnek-e. Ha a webes API támogatja streamelést a nagyméretű bináris objektumokat (például videókat vagy hangfájlokat) visszaadó kérelmeknél, akkor ügyeljen arra, hogy az ügyfélkérelmek ne legyenek blokkolva az adatok streamelése közben. Ha a webes API hosszú ideig futó adatmódosítási műveletek lekérdezését valósítja meg, ellenőrizze, hogy a műveletek helyesen jelentik-e az állapotukat a folytatás során.

Emellett hozzon létre és futtasson teljesítményteszteket, amelyekkel ellenőrizheti, hogy a webes API kielégítően működik-e nagy terhelés alatt. Webes teljesítmény- és terheléses tesztelési projekteket a Visual Studio Ultimate használatával hozhat létre.

Az Azure API Management használata

Az Azure-ban fontolja meg az Azure API Management használatát egy webes API közzétételéhez és kezeléséhez. Ezzel az eszközzel létrehozhat egy olyan szolgáltatást, amely egy vagy több webes API előtér-szolgáltatásaként funkcionál. A szolgáltatás maga egy méretezhető webszolgáltatás, amelyet az Azure Portal használatával hozhat létre és konfigurálhat. A szolgáltatással a következőképpen tehet közzé és felügyelhet egy webes API-t:

  1. Telepítse az API-t egy webhelyre, Azure-felhőszolgáltatásba vagy Azure-beli virtuális gépre.

  2. Csatlakoztassa az API Management szolgáltatást a webes API-hoz. A felügyeleti API URL-címére küldött kérelmeket a webes API-ban lévő URI-kre képezi le a rendszer. Egy API Management szolgáltatás több webes API-hoz is irányíthatja a kérelmeket. Ezáltal több webes API-t összesíthet egyetlen felügyeleti szolgáltatásban. Hasonlóképp egy webes API-ra több API Management szolgáltatás is hivatkozhat, ha a különböző alkalmazások számára elérhető funkciókat korlátozni vagy particionálni kell.

    Feljegyzés

    A HTTP GET-kérelmekre adott válasz részeként létrehozott HATEOAS-hivatkozásokban az URI-knak az API felügyeleti szolgáltatás URL-címére kell hivatkoznia, nem pedig a webes API-t üzemeltető webkiszolgálóra.

  3. Minden webes API-hoz adja meg a közzétett HTTP-műveleteket, valamint a műveletek által bemenetként felhasználható opcionális paramétereket. Azt is beállíthatja, hogy az API Management szolgáltatás gyorsítótárazza-e a webes API-tól kapott választ, így optimalizálhatja az ugyanazon adatokra irányuló ismétlődő kérelmeket. Rögzítse az egyes műveletek által adható HTTP-válaszok részleteit. Ezek az adatok a fejlesztői dokumentációk létrehozására szolgálnak, ezért fontos hogy pontosak és teljesek legyenek.

    A műveleteket manuálisan is definiálhatja az Azure Portal által biztosított varázslókkal, vagy importálhatja őket egy WADL vagy Swagger formátumú definíciókat tartalmazó fájlból.

  4. Konfigurálja az API Management szolgáltatás és a webes API-t üzemeltető webkiszolgáló közötti kommunikáció biztonsági beállításait. Az API Management szolgáltatás jelenleg támogatja a tanúsítványokkal végzett alapszintű hitelesítést és kölcsönös hitelesítést, valamint az OAuth 2.0 felhasználói hitelesítést.

  5. Hozzon létre egy terméket. A termék a közzététel egysége: azokat a webes API-kat kell hozzáadnia, amelyeket korábban csatlakoztatott a kezelési szolgáltatáshoz. A termék közzététele után a webes API-k elérhetővé válnak a fejlesztők számára.

    Feljegyzés

    A termék közzététele előtt megadhat felhasználói csoportokat, amelyek hozzáférhetnek a termékhez, és felhasználókat adhat a csoportokhoz. Ezzel szabályozható, hogy a webes API-t mely fejlesztők és alkalmazások használhatják. Ha a webes API-t jóvá kell hagyni, a hozzáférés előtt a fejlesztőknek kérelmet kell küldeniük a termék adminisztrátorának. A rendszergazda engedélyezheti vagy megtagadhatja a fejlesztő hozzáférését. A már engedélyezett fejlesztők is blokkolhatók, ha a körülmények megváltoznak.

  6. Konfiguráljon szabályzatokat minden webes API-hoz. A szabályzatok meghatározzák például, hogy a tartományok közötti hívások engedélyezettek-e, hogy hogyan zajlik az ügyfelek hitelesítése, hogy az XML és JSON formátumok közötti átalakítás transzparens módon történik-e, hogy egy adott IP-címtartomány hívásai korlátozva legyenek-e, hogy a hívások sebessége korlátozott legyen-e, valamint a használati kvótákat. A szabályzatok alkalmazhatók globálisan az egész termékre, a termékben lévő adott webes API-ra, vagy a webes API-k egyes műveleteire.

További információkért tekintse meg az API Management dokumentációját.

Tipp.

Az Azure az Azure Traffic Manager segítségével teszi lehetővé a feladatátvétel és a terheléselosztás megvalósítását, valamint egy webhely különböző földrajzi helyeken üzemeltetett példányai közötti késés csökkentését. Az Azure Traffic Manager az API Management szolgáltatással együtt használható: az API Management az Azure Traffic Manager segítségével irányítja egy webhely példányaira küldött kérelmek útválasztását. További információ: Traffic Manager útválasztási módszerek.

Ebben a struktúrában, ha egyéni DNS-neveket használ a webhelyekhez, minden webhelyhez konfigurálnia kell a megfelelő CNAME rekordot, hogy az Az Azure Traffic Manager webhely DNS-nevére mutasson.

Ügyféloldali fejlesztők támogatása

Az ügyfélalkalmazások fejlesztőinek általában információkra van szükségük a webes API elérésével kapcsolatban. Emellett dokumentációra is szükségük van a paraméterekről, adattípusokról, visszatérési típusokról és visszatérési kódokról, amelyek leírják a webszolgáltatás és az ügyfélalkalmazás között küldött különböző kérelmeket és válaszokat.

A webes API-k REST-műveleteinek dokumentálása

Az Azure API Management szolgáltatás tartalmaz egy fejlesztői portált, amely leírja a webes API-k által elérhetővé tett REST-műveleteket. A közzétett termékek megjelennek a portálon. A fejlesztők ezen a portálon regisztrálhatnak hozzáférésért, majd a rendszergazda jóváhagyhatja vagy visszautasítja a kérelmüket. Ha a fejlesztőnek jóváhagyták a kérelmét, kap egy előfizetési kulcsot, amellyel hitelesítheti az általa fejlesztett ügyfélalkalmazások hívásait. Ezt a kulcsot meg kell adni minden webes API-hívással, máskülönben a rendszer elutasítja a hívást.

A portál a következőket is tartalmazza:

  • A termék dokumentációja, a termék által elérhetővé tett műveletek listája, a szükséges paraméterek és a különböző visszaadható válaszok. Vegye figyelembe, hogy ezek az információk a „Webes API közzététele a Microsoft Azure API Management szolgáltatással” című szakaszban található lista 3. lépésében megadott információ alapján jönnek létre.
  • Kódrészletek, amelyek bemutatják a műveletek meghívását számos nyelvből, köztük a JavaScript, C#, Java, Ruby, Python, és PHP nyelvekből.
  • Egy fejlesztői konzol, amely lehetővé teszi a fejlesztőknek a termékműveletek HTTP-kérelmek küldésével való tesztelését, valamint az eredmények megtekintését.
  • Egy oldal, ahol a fejlesztők jelenthetik a talált hibákat és problémákat.

Az Azure Portal lehetővé teszi a fejlesztői portál testreszabását, hogy a cég arculatának megfelelően módosítsa a stílust és az elrendezést.

Ügyféloldali SDK megvalósítása

Ha olyan ügyfélalkalmazást hoz létre, amely REST-kérelmek meghívásával ér el egy webes API-t, nagy mennyiségű kódot kell írni az egyes kérelmek létrehozásához, megfelelő formázásához és a webszolgáltatást futtató kiszolgálóra való elküldéséhez, valamint a válasz elemzéséhez, a kérelem sikerességének vagy sikertelenségének megállapításához és a visszaadott adatok kinyeréséhez. Ha el kívánja szigetelni az ügyfélalkalmazást ezektől a problémáktól, megadhat egy SDK-t, amely becsomagolja a REST-felületet, és egy jobban használható metódusgyűjteménybe foglalja ezeket a részleteket. Az ügyfélalkalmazások felhasználhatják ezeket a metódusokat, amelyek transzparens módon átalakítják a hívásokat REST-kérelmekké, majd a válaszokat visszaalakítják a metódusok által visszaadott értékekké. Ez egy elterjedt megoldás, amelyet számos szolgáltatás használ, köztük az Azure SDK is.

Egy ügyféloldali SDK létrehozása jelentős vállalkozás, mivel egységes megvalósítást és alapos tesztelést igényel. Azonban a folyamat nagy része gépesíthető, és sok beszállító kínál olyan eszközöket, amelyekkel számos feladat automatizálható.

Webes API monitorozása

Attól függően, hogy a webes API hogyan lett közzétéve és üzembe helyezve, monitorozhatja az API-t közvetlenül, vagy felhasználási és állapotadatokat gyűjthet az API Management szolgáltatáson áthaladó forgalom elemzésével.

Webes API közvetlen monitorozása

Ha a webes API megvalósításához az ASP.NET Web API-sablont (akár webes API-projektként, akár egy Azure-felhőszolgáltatáson belüli webes szerepkörként) és a Visual Studio 2013-at használta, akkor az ASP.NET Application Insights segítségével adatokat gyűjthet a webes API rendelkezésre állásáról, teljesítményéről és használatáról. Az Application Insights egy olyan csomag, amely transzparens módon nyomon követi és rögzíti a kérelmek és válaszok adatait, ha a webes API a felhőben lett üzembe helyezve. A csomag telepítése és konfigurálása után nem szükséges módosítani a webes API kódját a használatához. Ha a webes API-t egy Azure-webhelyen telepíti, a rendszer minden forgalmat megvizsgál, és a következő statisztikákat gyűjti össze:

  • kiszolgáló válaszideje,
  • kiszolgáló kérelmeinek száma és az egyes kérelmek részletei,
  • a leglassabb kérelmek átlagos válaszidő alapján,
  • a sikertelen kérelmek részletei,
  • a különböző böngészők és felhasználói ügynökök által kezdeményezett munkamenetek száma,
  • a leggyakrabban megtekintett lapok (ez nem elsősorban a webes API-khoz, hanem a webalkalmazásokhoz hasznos).
  • a webes API-hoz hozzáférő különböző felhasználói szerepkörök.

Ezeket az adatokat valós időben tekintheti meg az Azure Portalon. Olyan webes teszteket is létrehozhat, amelyek a webes API állapotát figyelik. A webes teszt rendszeres kérést küld egy adott URI-nak a webes API-ban, és rögzíti a választ. Meghatározhatja, mi számít sikeres válasznak (például a 200-as HTTP-állapotkód), és beállíthatja, hogy ha a kérelem nem ezt a választ adja vissza, a rendszer küldjön riasztást egy rendszergazdának. Szükség esetén a rendszergazda újraindíthatja a webes API-t futtató kiszolgálót, ha meghibásodott.

További információ: Application Insights – Az ASP.NET használatának első lépései.

Webes API monitorozása az API Management szolgáltatáson keresztül

Ha a webes API-t az API Management szolgáltatással tette közzé, az Azure Portal API Management oldala tartalmaz egy irányítópultot, amely lehetővé teszi a szolgáltatás általános teljesítményének megtekintését. Az Elemzés oldalon részletes elemzések találhatók a termék használatáról. Ez az oldal a következő lapokat tartalmazza:

  • Használat – Ez a lap információkat közöl az API-hívások számáról és az ezek kezeléséhez igénybe vett sávszélességről. A használati adatok szűrhetők termék, API és művelet szerint.
  • Állapot – Ezen a lapon megtekinthetők az API-kérelmek eredményei (a visszaadott HTTP-állapotkódok), a gyorsítótárazási szabályzat hatékonysága, az API válaszideje és a szolgáltatás válaszideje. Az állapotadatok szintén szűrhetők termék, API és művelet szerint.
  • Tevékenység – Ez a lap szöveges összegzést tartalmaz a sikeres, sikertelen és blokkolt hívásokról, az átlagos válaszidőről, valamint az egyes termékek, webes API-k és műveletek válaszidejéről. Emellett az oldal az egyes fejlesztők által indított hívások számát is felsorolja.
  • Áttekintés – Ez a lap a teljesítményadatok összegzését tartalmazza, beleértve a legtöbb API-hívást indító fejlesztőket, és az e hívásokat fogadó termékeket, webes API-kat és műveleteket.

Ezen adatok alapján lehet megállapítani, hogy egy adott webes API vagy művelet szűk keresztmetszetet okoz-e, majd szükség esetén skálázhatja a gazdakörnyezetet további kiszolgálókkal. Emellett az is megállapítható, ha egy vagy több alkalmazás aránytalanul nagy mennyiségű erőforrást használ, majd a megfelelő szabályzatokkal kvóták állíthatók be és korlátozható a hívások gyakorisága.

Feljegyzés

A közzétett termékek részleteinek módosításai azonnal hatályba lépnek. Például egy webes API-hoz hozzáadhat vagy eltávolíthat egy műveletet anélkül, hogy újra közzé kellene tennie a webes API-t tartalmazó terméket.

Következő lépések