Реализация APIAPI implementation

Тщательно разработанной веб-API RESTful определяет ресурсы, связи и схемы навигации, которые доступны для клиентских приложений.A carefully designed RESTful web API defines the resources, relationships, and navigation schemes that are accessible to client applications. При реализации и развертывании веб-API следует учитывать физические требования среды размещения веб-API и способ создания веб-API, а не логическую структуру данных.When you implement and deploy a web API, you should consider the physical requirements of the environment hosting the web API and the way in which the web API is constructed rather than the logical structure of the data. В этом руководстве рассматриваются советы и рекомендации по реализации веб-API и его публикации, чтобы сделать API доступными для клиентских приложений.This guidance focuses on best practices for implementing a web API and publishing it to make it available to client applications. Подробные сведения о разработке веб-API см. в разделе руководство по проектированию API.For detailed information about web API design, see API design guidance.

Обработка запросовProcessing requests

При реализации кода для обработки запросов следует учитывать перечисленные ниже аспекты.Consider the following points when you implement the code to handle requests.

Идемпотентность действий GET, PUT, DELETE, HEAD и PATCHGET, PUT, DELETE, HEAD, and PATCH actions should be idempotent

Код, который реализует эти запросы, не должен включать никаких побочных эффектов.The code that implements these requests should not impose any side-effects. Один и тот же запрос, выполненный повторно через тот же ресурс, должен возвращать результат в том же состоянии.The same request repeated over the same resource should result in the same state. Например, несколько запросов на удаление с одним URI-адресом должны выполнять одинаковое действие, хотя возвращаемые коды состояния HTTP могут отличаться.For example, sending multiple DELETE requests to the same URI should have the same effect, although the HTTP status code in the response messages may be different. Например, первый запрос DELETE вернет код состояния 204 (нет содержимого), а все последующие аналогичные запросы DELETE — код состояния 404 (не найдено).The first DELETE request might return status code 204 (No Content), while a subsequent DELETE request might return status code 404 (Not Found).

Примечание

В статье, посвященной шаблонам идемпотентности , в блоге Джонатана Оливера (Jonathan Oliver) представлен обзор идемпотентности и его связь с операциями по управлению данными.The article Idempotency Patterns on Jonathan Oliver’s blog provides an overview of idempotency and how it relates to data management operations.

Отсутствие несвязанных побочных эффектов у действий POST, которые создают новые ресурсыPOST actions that create new resources should not have unrelated side-effects

Если запрос POST предназначен для создания нового ресурса, результаты запроса должны быть ограничены в новый ресурс (и возможно все непосредственно связанные ресурсы Если какую-либо компоновки участвует) например, в системе электронной коммерции в запросе POST, Создает новый заказ для клиента также может изменить уровни запасов и формирования сведений о выставлении счетов, но его не следует изменять сведения, не связанные непосредственно с порядок или иметь никаких других побочных эффектов на общее состояние системы.If a POST request is intended to create a new resource, the effects of the request should be limited to the new resource (and possibly any directly related resources if there is some sort of linkage involved) For example, in an e-commerce system, a POST request that creates a new order for a customer might also amend inventory levels and generate billing information, but it should not modify information not directly related to the order or have any other side-effects on the overall state of the system.

Нежелательность реализации множественных операции POST, PUT и DELETEAvoid implementing chatty POST, PUT, and DELETE operations

Реализуйте поддержку запросов POST, PUT и DELETE через коллекции ресурсов.Support POST, PUT and DELETE requests over resource collections. Запрос POST может содержать сведения о нескольких новых ресурсах и добавить их все в одну и ту же коллекцию, запрос PUT может заменить весь набор ресурсов в коллекции, а запрос DELETE может удалить всю коллекцию.A POST request can contain the details for multiple new resources and add them all to the same collection, a PUT request can replace the entire set of resources in a collection, and a DELETE request can remove an entire collection.

Поддержка OData, включенная в веб-API ASP.NET 2, позволяет создавать пакеты запросов.The OData support included in ASP.NET Web API 2 provides the ability to batch requests. Клиентское приложение может упаковать несколько запросов веб-API и отправлять их на сервер в одном HTTP-запросе, а также получать один ответ HTTP, который содержит ответы на каждый запрос.A client application can package up several web API requests and send them to the server in a single HTTP request, and receive a single HTTP response that contains the replies to each request. Дополнительные сведения введение поддержки пакетной службы в веб-API и веб-API OData.For more information, Introducing batch support in Web API and Web API OData.

Соблюдение спецификаций протокола HTTP при отправке ответовFollow the HTTP specification when sending a response

Веб-интерфейс API должен возвращать сообщения, содержащие правильный код состояния HTTP, чтобы клиент мог определить способ обработки результатов, соответствующие заголовки HTTP, чтобы клиент мог понять характер результата, и подходящим образом форматированный текст, чтобы клиент мог проанализировать результат.A web API must return messages that contain the correct HTTP status code to enable the client to determine how to handle the result, the appropriate HTTP headers so that the client understands the nature of the result, and a suitably formatted body to enable the client to parse the result.

Однако в этом случае операция POST должна возвращать код состояния 201 (создано), а ответное сообщение должно содержать URI созданного ресурса в заголовке Location.For example, a POST operation should return status code 201 (Created) and the response message should include the URI of the newly created resource in the Location header of the response message.

Поддержка согласования содержимогоSupport content negotiation

Текст ответного сообщения может содержать данные в различных форматах.The body of a response message may contain data in a variety of formats. Например, запрос HTTP GET может возвращать данные в формате JSON или в формате XML.For example, an HTTP GET request could return data in JSON, or XML format. Когда клиент отправляет запрос, он может включить заголовок Accept, указывающий форматы данных, которые он может обработать.When the client submits a request, it can include an Accept header that specifies the data formats that it can handle. Эти форматы задаются в виде типов мультимедиа.These formats are specified as media types. Например, клиент, отправляющий запрос GET, который извлекает изображения, может указать заголовок Accept, перечисляющий типы мультимедиа, которые может обработать клиент, например image/jpeg, image/gif, image/png.For example, a client that issues a GET request that retrieves an image can specify an Accept header that lists the media types that the client can handle, such as image/jpeg, image/gif, image/png. Когда веб-API возвращает результат, ему следует форматировать данные с помощью одного из этих типов мультимедиа и указать формат в заголовке Content-Type ответа.When the web API returns the result, it should format the data by using one of these media types and specify the format in the Content-Type header of the response.

Если клиент не указывает заголовок Accept, то используйте формат по умолчанию для текста ответа.If the client does not specify an Accept header, then use a sensible default format for the response body. Например, платформа веб-API ASP.NET по умолчанию использует для текстовых данных формат JSON.As an example, the ASP.NET Web API framework defaults to JSON for text-based data.

Методика HATEOAS позволяет клиенту обнаружить ресурсы и перейти к ним из исходной стартовой точки.The HATEOAS approach enables a client to navigate and discover resources from an initial starting point. Это достигается за счет использования ссылок, содержащих URI; когда клиент отправляет запрос HTTP GET, чтобы получить доступ к ресурсу, ответ должен содержать URI, которые позволяют клиентскому приложению быстро найти все непосредственно связанные ресурсы.This is achieved by using links containing URIs; when a client issues an HTTP GET request to obtain a resource, the response should contain URIs that enable a client application to quickly locate any directly related resources. Например, в веб-API с поддержкой решения электронной коммерции заказчик может разместить много заказов.For example, in a web API that supports an e-commerce solution, a customer may have placed many orders. Когда клиентское приложение получает сведения о заказчике, ответ должен содержать ссылки, позволяющие первому отправлять запросы HTTP GET для извлечения этих заказов.When a client application retrieves the details for a customer, the response should include links that enable the client application to send HTTP GET requests that can retrieve these orders. Кроме того, ссылки в стиле HATEOAS должны содержать описания других операций (POST, PUT, DELETE и т. д.), которые поддерживает каждый связанный ресурс, а также соответствующий URI для выполнения каждого запроса.Additionally, HATEOAS-style links should describe the other operations (POST, PUT, DELETE, and so on) that each linked resource supports together with the corresponding URI to perform each request. Этот подход описан более подробно в по проектированию API.This approach is described in more detail in API design.

В настоящее время отсутствуют стандарты, определяющие реализацию HATEOAS, однако в следующем примере показан один из возможных способов.Currently there are no standards that govern the implementation of HATEOAS, but the following example illustrates one possible approach. В этом примере запрос HTTP GET, который находит сведения о заказчике возвращает ответ, включающий ссылки HATEOAS, которые ссылаются на заказов для него:In this example, an HTTP GET request that finds the details for a customer returns a response that includes HATEOAS links that reference the orders for that customer:

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

В этом примере данные заказчика, представленные классом Customer , показаны в следующем фрагменте кода.In this example, the customer data is represented by the Customer class shown in the following code snippet. Ссылки HATEOAS находятся в свойстве Links коллекции:The HATEOAS links are held in the Links collection property:

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 получает данные заказчика из хранилища и создает объект Customer, а затем заполняет коллекцию Links.The HTTP GET operation retrieves the customer data from storage and constructs a Customer object, and then populates the Links collection. Результат представляется в формате ответного сообщения JSON.The result is formatted as a JSON response message. Каждая ссылка включает в себя следующие поля:Each link comprises the following fields:

  • связь возвращаемого объекта с объектом, описанным в ссылке;The relationship between the object being returned and the object described by the link. в этом случае self указывает, что ссылка является ссылкой на сам объект (аналогично указателю this во многих языках объектно-ориентированного программирования), а orders — это имя коллекции со сведениями, связанными с заказом;In this case self indicates that the link is a reference back to the object itself (similar to a this pointer in many object-oriented languages), and orders is the name of a collection containing the related order information.
  • гиперссылка (Href) для объекта, описываемого в ссылке в виде URI;The hyperlink (Href) for the object being described by the link in the form of a URI.
  • тип HTTP-запроса (Action), который можно отправлять на этот URI;The type of HTTP request (Action) that can be sent to this URI.
  • формат данных (Types), который необходимо предоставить в HTTP-запросе или которые могут быть возвращены в ответе, в зависимости от типа запроса.The format of any data (Types) that should be provided in the HTTP request or that can be returned in the response, depending on the type of the request.

Ссылки HATEOAS, показанные в примере HTTP-ответа, указывают на то, что клиентское приложение может выполнять следующие операции:The HATEOAS links shown in the example HTTP response indicate that a client application can perform the following operations:

  • Запрос HTTP GET к URI https://adventure-works.com/customers/2 для получения сведений о заказчике (повторно).An HTTP GET request to the URI https://adventure-works.com/customers/2 to fetch the details of the customer (again). данные могут быть возвращены в формате XML или JSON;The data can be returned as XML or JSON.
  • Запрос HTTP PUT к URI https://adventure-works.com/customers/2 для изменения сведений о заказчике.An HTTP PUT request to the URI https://adventure-works.com/customers/2 to modify the details of the customer. новые данные должны быть представлены в сообщении запроса в формате x-www-form-urlencoded;The new data must be provided in the request message in x-www-form-urlencoded format.
  • Запрос HTTP DELETE к URI https://adventure-works.com/customers/2 для удаления заказчика.An HTTP DELETE request to the URI https://adventure-works.com/customers/2 to delete the customer. запрос не ожидает никаких дополнительных сведений или возврата данных в теле ответного сообщения;The request does not expect any additional information or return data in the response message body.
  • Запрос HTTP GET к URI https://adventure-works.com/customers/2/orders для поиска всех заказов заказчика.An HTTP GET request to the URI https://adventure-works.com/customers/2/orders to find all the orders for the customer. данные могут быть возвращены в формате XML или JSON;The data can be returned as XML or JSON.
  • Запрос HTTP PUT к URI https://adventure-works.com/customers/2/orders для создания нового заказа для заказчика.An HTTP PUT request to the URI https://adventure-works.com/customers/2/orders to create a new order for this customer. данные должны быть представлены в сообщении запроса в формате x-www-form-urlencoded.The data must be provided in the request message in x-www-form-urlencoded format.

Обработка исключенийHandling exceptions

Если операция создает неперехваченное исключение, учитывайте следующие аспекты.Consider the following points if an operation throws an uncaught exception.

Перехват всех исключений и возвращение пользователям информативных сообщенийCapture exceptions and return a meaningful response to clients

Код, который реализует операцию HTTP, должен полностью обрабатывать все исключения и не оставлять их обработку платформе.The code that implements an HTTP operation should provide comprehensive exception handling rather than letting uncaught exceptions propagate to the framework. Если исключение не позволяет успешно завершить операцию, его можно передать обратно в ответное сообщение, однако при этом оно должно включать значимое описание ошибки, вызвавшей исключение.If an exception makes it impossible to complete the operation successfully, the exception can be passed back in the response message, but it should include a meaningful description of the error that caused the exception. Исключение также должно включать соответствующий код состояния HTTP, а не просто возвращаемый код состояния 500 для каждого случая.The exception should also include the appropriate HTTP status code rather than simply returning status code 500 for every situation. Например, если запрос пользователя приводит к обновлению базы данных, что нарушает ограничение (например, при попытке удалить заказчика, имеющего необработанные заказы), следует возвращать код состояния 409 (конфликт) и текст сообщения с указанием причины конфликта кода.For example, if a user request causes a database update that violates a constraint (such as attempting to delete a customer that has outstanding orders), you should return status code 409 (Conflict) and a message body indicating the reason for the conflict. Если же запрос определяется как невыполнимый по иной причине, можно возвратить код состояния 400 (неправильный запрос).If some other condition renders the request unachievable, you can return status code 400 (Bad Request). Полный список кодов состояния HTTP можно найти на определения кодов состояния на веб-сайте консорциума W3C.You can find a full list of HTTP status codes on the Status code definitions page on the W3C website.

Следующий пример кода перехватывает разные условия и возвращает соответствующие ответы.The code example traps different conditions and returns an appropriate response.

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

Совет

Не включайте в эти ответы сведения, которые могут использовать злоумышленники для взлома вашего API.Do not include information that could be useful to an attacker attempting to penetrate your API.

Многие веб-серверы перехвата ошибки сами до попадания в веб-API.Many web servers trap error conditions themselves before they reach the web API. Например, если вы настроили проверку подлинности на веб-сайте и пользователь указал неправильные сведения для проверки подлинности, то веб-сервер должен предоставить ответ с кодом состояния 401 (отсутствует авторизация).For example, if you configure authentication for a web site and the user fails to provide the correct authentication information, the web server should respond with status code 401 (Unauthorized). После проверки подлинности клиента код может выполнить собственные проверки, чтобы убедиться, что клиенту можно предоставить доступ к запрашиваемому ресурсу.Once a client has been authenticated, your code can perform its own checks to verify that the client should be able access the requested resource. В случае сбоя проверки подлинности следует возвращать код состояния 403 (запрещено).If this authorization fails, you should return status code 403 (Forbidden).

Согласованная обработка исключений и внесение в журнал сведений об ошибкахHandle exceptions consistently and log information about errors

Для обработки исключений согласованным способом рассмотрите возможность применения глобальной стратегии обработки ошибок в рамках всего веб-API.To handle exceptions in a consistent manner, consider implementing a global error handling strategy across the entire web API. Кроме того, следует включить ведение журнала для записи подробных сведений о каждом исключении; этот журнал ошибок может содержать подробные сведения до тех пор, пока он не станет доступен клиентам через Интернет.You should also incorporate error logging which captures the full details of each exception; this error log can contain detailed information as long as it is not made accessible over the web to clients.

Раздельная обработка ошибок на стороне клиента и на стороне сервераDistinguish between client-side errors and server-side errors

Протокол HTTP позволяет различать ошибки, возникающие из-за клиентского приложения (коды состояния HTTP 4xx), и ошибки, вызванные неполадками на сервере (коды состояния HTTP 5xx).The HTTP protocol distinguishes between errors that occur due to the client application (the HTTP 4xx status codes), and errors that are caused by a mishap on the server (the HTTP 5xx status codes). Обязательно учитывайте это при обработке ответных сообщений об ошибках.Make sure that you respect this convention in any error response messages.

Оптимизация доступа к данным на стороне клиентаOptimizing client-side data access

В распределенной среде, например, включающей веб-сервер и клиентские приложения, одним из основных источников проблем является сеть.In a distributed environment such as that involving a web server and client applications, one of the primary sources of concern is the network. Это может оказаться значительным узким местом, особенно в том случае, если клиентское приложение часто отправляет запросы или получает данные.This can act as a considerable bottleneck, especially if a client application is frequently sending requests or receiving data. Поэтому следует стремиться к тому, чтобы свести к минимуму объем трафика, проходящего через сеть.Therefore you should aim to minimize the amount of traffic that flows across the network. При реализации кода для получения и хранения данных необходимо учитывать перечисленные ниже моменты.Consider the following points when you implement the code to retrieve and maintain data:

Поддержка кэширования на стороне клиентаSupport client-side caching

Протокол HTTP 1.1 поддерживает кэширование в клиентах и на промежуточных серверах, через которые направляется запрос, с помощью заголовка Cache-Control.The HTTP 1.1 protocol supports caching in clients and intermediate servers through which a request is routed by the use of the Cache-Control header. Когда клиентское приложение отправляет в веб-API запрос HTTP GET, ответ может включать заголовок Cache-Control. Этот заголовок указывает, могут ли данные в теле ответа безопасно кэшироваться клиентом или промежуточным сервером, через который был направлен запрос, и как долго следует кэшировать данные, прежде чем срок их действия истечет и они будут считаться устаревшими.When a client application sends an HTTP GET request to the web API, the response can include a Cache-Control header that indicates whether the data in the body of the response can be safely cached by the client or an intermediate server through which the request has been routed, and for how long before it should expire and be considered out-of-date. В следующем примере показан запрос HTTP GET и соответствующий ответ, который включает заголовок Cache-Control:The following example shows an HTTP GET request and the corresponding response that includes a Cache-Control header:

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}

В этом примере заголовок Cache-Control указывает, что срок действия возвращенных данных составляет 600 секунд, а сами данные предназначены только для одного клиента и не должны храниться в общем кэше, используемом другими клиентами (определяется параметром private).In this example, the Cache-Control header specifies that the data returned should be expired after 600 seconds, and is only suitable for a single client and must not be stored in a shared cache used by other clients (it is private). В заголовке Cache-Control должен быть указан параметр public вместо private, чтобы данные хранились в общем кэше. Также может быть указан параметр no-store, чтобы данные не кэшировались клиентом.The Cache-Control header could specify public rather than private in which case the data can be stored in a shared cache, or it could specify no-store in which case the data must not be cached by the client. В следующем примере кода показано, как создать заголовок Cache-Control в ответном сообщении:The following code example shows how to construct a Cache-Control header in a response message:

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

Этот код использует пользовательский IHttpActionResult класс с именем OkResultWithCaching.This code uses a custom IHttpActionResult class named OkResultWithCaching. Этот класс позволяет контроллеру задавать содержимое заголовка кэша:This class enables the controller to set the cache header contents:

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

Примечание

Протокол HTTP также определяет директиву no-cache для заголовка Cache-Control.The HTTP protocol also defines the no-cache directive for the Cache-Control header. Директива может ввести в заблуждение, поскольку означает не "не следует кэшировать", а "повторно проверить кэшированные данные на сервере перед их возвращением"; данные по-прежнему могут кэшироваться, но каждый раз, когда они используются, данные проверяются на предмет своей актуальности.Rather confusingly, this directive does not mean "do not cache" but rather "revalidate the cached information with the server before returning it"; the data can still be cached, but it is checked each time it is used to ensure that it is still current.

Управление кэшем — это задача клиентского приложения или промежуточного сервера, однако при правильной реализации это позволяет сэкономить пропускную способность и повысить производительность за счет устранения необходимости в выборке данных, которые уже были получены недавно.Cache management is the responsibility of the client application or intermediate server, but if properly implemented it can save bandwidth and improve performance by removing the need to fetch data that has already been recently retrieved.

Значение max-age в заголовке Cache-Control носит исключительно информационный характер. Оно не гарантирует неизменность соответствующих данных в течение указанного времени.The max-age value in the Cache-Control header is only a guide and not a guarantee that the corresponding data won't change during the specified time. Веб-API следует задать для параметра max-age подходящее значение в зависимости от ожидаемой изменчивости данных.The web API should set the max-age to a suitable value depending on the expected volatility of the data. По истечении этого периода клиент удаляет объект из кэша.When this period expires, the client should discard the object from the cache.

Примечание

Большинство современных веб-браузеров поддерживают кэширование на стороне клиента за счет добавления соответствующих заголовков cache-control в запросы и проверки заголовков результатов, как описано в этой статье.Most modern web browsers support client-side caching by adding the appropriate cache-control headers to requests and examining the headers of the results, as described. Однако некоторые устаревшие браузеры не будут кэшировать значения, возвращаемые из URL-адреса, который включает строку запроса.However, some older browsers will not cache the values returned from a URL that includes a query string. Обычно это не является проблемой для пользовательских клиентских приложений, реализующих собственные стратегии управления кэшем на основе протокола, описанного здесь.This is not usually an issue for custom client applications which implement their own cache management strategy based on the protocol discussed here.

Некоторые устаревшие прокси-серверы демонстрируют такое же поведение и могут не кэшировать запросы на основе URL-адреса со строками запросов.Some older proxies exhibit the same behavior and might not cache requests based on URLs with query strings. Это может оказаться проблемой для пользовательских клиентских приложений, подключающихся к веб-серверу через такой прокси-сервер.This could be an issue for custom client applications that connect to a web server through such a proxy.

Применение тегов сущностей для оптимизации обработки запросовProvide ETags to optimize query processing

Когда клиентское приложение получает объект, ответное сообщение также может содержать элемент ETag (тег сущности).When a client application retrieves an object, the response message can also include an ETag (Entity Tag). ETag представляет собой непрозрачную строку, в которой указывается версия ресурса; при каждом изменении ресурса изменяется и его ETag.An ETag is an opaque string that indicates the version of a resource; each time a resource changes the Etag is also modified. Этот ETag должен кэшироваться клиентским приложением как часть данных.This ETag should be cached as part of the data by the client application. В следующем примере кода показано, как добавить ETag в ответ на запрос HTTP GET.The following code example shows how to add an ETag as part of the response to an HTTP GET request. Этот код использует метод GetHashCode объекта для формирования числового значения, идентифицирующего объект (при необходимости этот метод можно переопределить и создать собственный хэш с помощью такого алгоритма, как MD5):This code uses the GetHashCode method of an object to generate a numeric value that identifies the object (you can override this method if necessary and generate your own hash using an algorithm such as MD5) :

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

Ответное сообщение, отправленное веб-API, выглядит следующим образом:The response message posted by the web API looks like this:

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}

Совет

По соображениям безопасности запретите кэширование конфиденциальных данные или данных, возвращаемых через подключение с проверкой подлинности (HTTPS).For security reasons, do not allow sensitive data or data returned over an authenticated (HTTPS) connection to be cached.

Клиентское приложение может в любое время выдать последующий запрос GET для получения того же ресурса, и если ресурс был изменен (имеет разные теги ETag), кэшированную версию следует удалить и добавить в кэш новую версию.A client application can issue a subsequent GET request to retrieve the same resource at any time, and if the resource has changed (it has a different ETag) the cached version should be discarded and the new version added to the cache. Если ресурс большой и для передачи его обратно клиенту требуется значительный объем пропускной способности, повторная отправка запросов для получения тех же данных может оказаться неэффективной.If a resource is large and requires a significant amount of bandwidth to transmit back to the client, repeated requests to fetch the same data can become inefficient. Для решения этой проблемы протокол HTTP определяет следующий процесс оптимизации запросов GET, которые должны поддерживать в веб-API:To combat this, the HTTP protocol defines the following process for optimizing GET requests that you should support in a web API:

  • Клиент создает запрос GET, содержащий ETag для кэшированной в настоящее время версии ресурса, указанный в заголовке HTTP If-None-Match:The client constructs a GET request containing the ETag for the currently cached version of the resource referenced in an If-None-Match HTTP header:

    GET https://adventure-works.com/orders/2 HTTP/1.1
    If-None-Match: "2147483648"
    
  • Операция GET в веб-API получает текущий ETag для запрошенных данных (заказ 2 в примере выше) и сравнивает его со значением заголовка If-None-Match.The GET operation in the web API obtains the current ETag for the requested data (order 2 in the above example), and compares it to the value in the If-None-Match header.

  • Если текущий ETag для запрошенных данных соответствует тегу ETag, предоставленному в запросе, то это означен, что ресурс не был изменен, а веб-API должен возвратить ответ HTTP с пустым текстом и кодом состояния 304 (не изменено).If the current ETag for the requested data matches the ETag provided by the request, the resource has not changed and the web API should return an HTTP response with an empty message body and a status code of 304 (Not Modified).

  • Если текущий ETag для запрошенных данных не соответствует тегу ETag, предоставленному в запросе, то это означен, что данные были изменены, и веб-API должен возвратить ответ HTTP с новыми данными в теле сообщения и кодом состояния 200 (ОК).If the current ETag for the requested data does not match the ETag provided by the request, then the data has changed and the web API should return an HTTP response with the new data in the message body and a status code of 200 (OK).

  • Если запрошенные данные больше не существуют, веб-API должен возвратить ответ HTTP с кодом состояния 404 (не найдено).If the requested data no longer exists then the web API should return an HTTP response with the status code of 404 (Not Found).

  • Клиент использует код состояния для поддержания кэша в актуальном состоянии.The client uses the status code to maintain the cache. Если данные не изменились (код состояния 304), то объект может оставаться в кэше и клиентское приложение будет использовать эту версию объекта.If the data has not changed (status code 304) then the object can remain cached and the client application should continue to use this version of the object. Если данные изменились (код состояния 200), то кэшированный объект следует удалить и вставить новый.If the data has changed (status code 200) then the cached object should be discarded and the new one inserted. В случае отсутствия данных (код состояния 404) объекта следует удалить из кэша.If the data is no longer available (status code 404) then the object should be removed from the cache.

Примечание

Если заголовок ответа содержит заголовок Cache-Control с параметром no-store, то объект следует всегда удалять из кэша, независимо от кода состояния HTTP.If the response header contains the Cache-Control header no-store then the object should always be removed from the cache regardless of the HTTP status code.

Во фрагменте кода ниже показан метод FindOrderByID , расширенный для поддержки заголовка If-None-Match.The code below shows the FindOrderByID method extended to support the If-None-Match header. Обратите внимание, если заголовок If-None-Match опущен, то извлечение всегда выполняется в заданном порядке:Notice that if the If-None-Match header is omitted, the specified order is always retrieved:

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

Этот пример включает дополнительный настраиваемый класс IHttpActionResult с именем EmptyResultWithCaching.This example incorporates an additional custom IHttpActionResult class named EmptyResultWithCaching. Этот класс выступает в роли простой оболочки объекта HttpResponseMessage , которая не содержит текст ответа:This class simply acts as a wrapper around an HttpResponseMessage object that does not contain a response body:

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

Совет

В этом примере значение ETag для данных формируется путем хэширования данных, полученных из базового источника данных.In this example, the ETag for the data is generated by hashing the data retrieved from the underlying data source. Если ETag можно вычислить другим способом, можно дополнительно оптимизировать процесс, и данные необходимо извлекать из источника данных только, если они изменились.If the ETag can be computed in some other way, then the process can be optimized further and the data only needs to be fetched from the data source if it has changed. Этот подход особенно полезен, если имеется большой объем данных или доступ к источнику данных может привести к значительным задержкам (например, если источником данных является удаленная база данных).This approach is especially useful if the data is large or accessing the data source can result in significant latency (for example, if the data source is a remote database).

Применение тегов сущностей для поддержки оптимистической блокировкиUse ETags to Support Optimistic Concurrency

Чтобы включить обновление ранее кэшированных данных, протокол HTTP поддерживает стратегию оптимистичного параллелизма.To enable updates over previously cached data, the HTTP protocol supports an optimistic concurrency strategy. Если после выборки и кэширования ресурса клиентское приложение отправляет запрос PUT или DELETE для изменения или удаления ресурса, то такой запрос должен включать заголовок If-Match, который ссылается на ETag.If, after fetching and caching a resource, the client application subsequently sends a PUT or DELETE request to change or remove the resource, it should include in If-Match header that references the ETag. Затем веб-API может использовать эту информацию для определения того, был ли ресурс уже изменен другим пользователем после его получения и отправки соответствующего ответа обратно в клиентское приложение, следующим образом:The web API can then use this information to determine whether the resource has already been changed by another user since it was retrieved and send an appropriate response back to the client application as follows:

  • Клиент создает запрос PUT, содержащий сведения о новом ресурсе и ETag для кэшированной в настоящее время версии ресурса, который указан в заголовке HTTP If-Match.The client constructs a PUT request containing the new details for the resource and the ETag for the currently cached version of the resource referenced in an If-Match HTTP header. В следующем примере показан запрос PUT, который обновляет заказ:The following example shows a PUT request that updates an order:

    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
    
  • Операция PUT в веб-API получает текущий ETag для запрошенных данных (заказ 1 в примере выше) и сравнивает его со значением заголовка If-Match.The PUT operation in the web API obtains the current ETag for the requested data (order 1 in the above example), and compares it to the value in the If-Match header.

  • Если текущий ETag для запрошенных данных соответствует ETag, предоставленному в запросе, то это означает, что ресурс не был изменен и веб-API следует выполнить обновление и возвратить сообщение с кодом состояния HTTP 204 (нет содержимого) при успешном выполнении.If the current ETag for the requested data matches the ETag provided by the request, the resource has not changed and the web API should perform the update, returning a message with HTTP status code 204 (No Content) if it is successful. Ответ может включать заголовки Cache-Control и ETag для обновленной версии ресурса.The response can include Cache-Control and ETag headers for the updated version of the resource. Ответ всегда должен содержать заголовок Location, указывающий URI обновленного ресурса.The response should always include the Location header that references the URI of the newly updated resource.

  • Если текущий ETag для запрошенных данных не соответствует ETag, предоставленному в запросе, то это означает, что данные были изменены другим пользователем, поскольку была выполнена выборка, и веб-API должен вернуть ответ HTTP с пустым текстом и кодом состояния 412 (необходимое условие не выполнено).If the current ETag for the requested data does not match the ETag provided by the request, then the data has been changed by another user since it was fetched and the web API should return an HTTP response with an empty message body and a status code of 412 (Precondition Failed).

  • Если ресурс, который требуется обновить, больше не существует, веб-API должен возвратить ответ HTTP с кодом состояния 404 (не найдено).If the resource to be updated no longer exists then the web API should return an HTTP response with the status code of 404 (Not Found).

  • Клиент использует код состояния и заголовки ответа для поддержания кэша в актуальном состоянии.The client uses the status code and response headers to maintain the cache. Если данные были обновлены (код состояния 204), то объект может оставаться в кэше (при условии, что в заголовке Cache-Control отсутствует параметр no-store), однако ETag следует обновить.If the data has been updated (status code 204) then the object can remain cached (as long as the Cache-Control header does not specify no-store) but the ETag should be updated. Если данные были изменены другим пользователем (код состояния 412) или вообще не найдены (код состояния 404), то кэшированный объект следует удалить.If the data was changed by another user changed (status code 412) or not found (status code 404) then the cached object should be discarded.

В следующем примере кода показана реализация операции PUT для контроллера Orders:The next code example shows an implementation of the PUT operation for the Orders controller:

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

Совет

Использование заголовка If-Match вовсе необязательно, и если он не указан, веб-API будет всегда пытаться обновить указанный заказ, возможно, путем машинальной перезаписи обновления, внесенного другим пользователем.Use of the If-Match header is entirely optional, and if it is omitted the web API will always attempt to update the specified order, possibly blindly overwriting an update made by another user. Чтобы избежать проблем, связанных с потерей обновлений, всегда указывайте заголовок If-Match.To avoid problems due to lost updates, always provide an If-Match header.

Обработка больших запросов и ответовHandling large requests and responses

Возможны случаи, когда клиентское приложение должно выдавать запросы, в которых отправляется или получается большой объем данных (несколько мегабайт или даже больше).There may be occasions when a client application needs to issue requests that send or receive data that may be several megabytes (or bigger) in size. Ожидание завершения передачи такого объема данных может привести к тому, что клиентское приложение перестанет отвечать на запросы.Waiting while this amount of data is transmitted could cause the client application to become unresponsive. Если необходимо обрабатывать запросы, включающие значительные объемы данных, обязательно учитывайте указанные ниже моменты.Consider the following points when you need to handle requests that include significant amounts of data:

Оптимизация запросов и ответов, имеющих отношение к большим объектамOptimize requests and responses that involve large objects

Некоторые ресурсы могут быть большими объектами или включать большие поля (например, изображения или другие типы двоичных данных).Some resources may be large objects or include large fields, such as graphics images or other types of binary data. Веб-API должен поддерживать потоковую передачу для оптимизации отправки и загрузки этих ресурсов.A web API should support streaming to enable optimized uploading and downloading of these resources.

Протокол HTTP обеспечивает механизм поблочного кодирования для потоковой передачи больших объектов данных обратно клиенту.The HTTP protocol provides the chunked transfer encoding mechanism to stream large data objects back to a client. Когда клиент отправляет HTTP-запрос GET для крупного объекта, веб-API может отправить ответ через подключение HTTP поэтапно в виде фрагментов.When the client sends an HTTP GET request for a large object, the web API can send the reply back in piecemeal chunks over an HTTP connection. Длина данных в ответе может быть изначально неизвестна (она может быть сгенерирована), поэтому серверу, на котором размещен веб-API, следует отправить ответное сообщение с каждым фрагментом, указывающим заголовок Transfer-Encoding: Chunked, а не заголовок Content-Length.The length of the data in the reply may not be known initially (it might be generated), so the server hosting the web API should send a response message with each chunk that specifies the Transfer-Encoding: Chunked header rather than a Content-Length header. В свою очередь, клиентское приложение может получать каждый блок для создания ответа.The client application can receive each chunk in turn to build up the complete response. Когда сервер отправляет обратно последний фрагмент данных с нулевым размером, передача данных завершается.The data transfer completes when the server sends back a final chunk with zero size.

Один запрос может вернуть огромный объект, на обработку которого потребуются значительные ресурсы.A single request could conceivably result in a massive object that consumes considerable resources. Если в процессе потоковой передачи веб-API определяет, что объем данных в запросе превысил некоторые допустимые ограничения, можно отменить операцию и вернуть ответное сообщение с кодом состояния 413 (запрос слишком большая сущность).If during the streaming process the web API determines that the amount of data in a request has exceeded some acceptable bounds, it can abort the operation and return a response message with status code 413 (Request Entity Too Large).

Можно свести к минимуму размер больших объектов, передаваемых по сети, с помощью сжатия HTTP.You can minimize the size of large objects transmitted over the network by using HTTP compression. Такой подход позволяет сократить объем сетевого трафика и связанные с этим сетевые задержки, но для этого требуется дополнительная обработка на стороне клиента и на сервере, где размещен веб-API.This approach helps to reduce the amount of network traffic and the associated network latency, but at the cost of requiring additional processing at the client and the server hosting the web API. Например, клиентское приложение, которое ожидает получить сжатые данные, может включать заголовок запроса Accept-Encoding: gzip (также могут быть указаны другие алгоритмы сжатия данных).For example, a client application that expects to receive compressed data can include an Accept-Encoding: gzip request header (other data compression algorithms can also be specified). Если сервер поддерживает сжатие, он должен предоставлять в теле сообщения ответ с содержимым, хранящимся в формате GZIP, и заголовок ответа Content-Encoding: gzip.If the server supports compression it should respond with the content held in gzip format in the message body and the Content-Encoding: gzip response header.

Можно объединять закодированное сжатие с потоковой передачей; перед потоковой передачей данные сначала необходимо сжать, а затем указать в заголовках сообщений кодировку содержимого GZIP и поблочное кодирование.You can combine encoded compression with streaming; compress the data first before streaming it, and specify the gzip content encoding and chunked transfer encoding in the message headers. Кроме того, некоторые веб-серверы (такие как Internet Information Server) можно настроить на автоматическое сжатие HTTP-ответов, независимо от того, сжимает веб-API данные или нет.Also note that some web servers (such as Internet Information Server) can be configured to automatically compress HTTP responses regardless of whether the web API compresses the data or not.

Реализация частичных ответов для клиентов, которые не поддерживают асинхронные операцииImplement partial responses for clients that do not support asynchronous operations

В качестве альтернативы асинхронной потоковой передаче клиентское приложение может явно запросить данные для больших объектов в виде фрагментов, которые также называются частичными ответами.As an alternative to asynchronous streaming, a client application can explicitly request data for large objects in chunks, known as partial responses. Клиентское приложение отправляет запрос HTTP HEAD для получения сведений об объекте.The client application sends an HTTP HEAD request to obtain information about the object. Если веб-API поддерживает частичные ответы, ему следует отвечать на запрос HEAD ответным сообщением, содержащим заголовок Accept-Ranges и заголовок Content-Length, который указывает общий размер объекта, однако тело сообщения должно быть пустым.If the web API supports partial responses if should respond to the HEAD request with a response message that contains an Accept-Ranges header and a Content-Length header that indicates the total size of the object, but the body of the message should be empty. Клиентское приложение может использовать эти сведения для создания ряда запросов GET, которые указывают диапазон байтов для получения.The client application can use this information to construct a series of GET requests that specify a range of bytes to receive. Веб-API должен вернуть ответное сообщение с кодом состояния HTTP 206 (частичное содержимое), заголовок Content-Length, который указывает фактический объем данных, включенных в текст ответного сообщения, и заголовок Content-Range, который указывает, какую часть объекта (4000 до 8000 байт) представляют эти данные.The web API should return a response message with HTTP status 206 (Partial Content), a Content-Length header that specifies the actual amount of data included in the body of the response message, and a Content-Range header that indicates which part (such as bytes 4000 to 8000) of the object this data represents.

Запросы HTTP HEAD и частичные ответы описаны более подробно в по проектированию API.HTTP HEAD requests and partial responses are described in more detail in API design.

Отказ от отправки клиентским приложениям ненужных сообщений с кодом 100 (продолжение)Avoid sending unnecessary 100-Continue status messages in client applications

Клиентское приложение, которое собирается передать на сервер большой объем данных, может сначала определить, желает ли сервер фактически принять такой запрос.A client application that is about to send a large amount of data to a server may determine first whether the server is actually willing to accept the request. Перед отправкой данных клиентское приложение может отправить HTTP-запрос с заголовком Expect: 100-Continue, заголовком Content-Length, который указывает размер данных, но с пустым текстом сообщения.Prior to sending the data, the client application can submit an HTTP request with an Expect: 100-Continue header, a Content-Length header that indicates the size of the data, but an empty message body. Если сервер готов обработать запрос, он должен отправить ответное сообщение с кодом состояния HTTP 100 (продолжить).If the server is willing to handle the request, it should respond with a message that specifies the HTTP status 100 (Continue). Клиентское приложение затем может продолжить выполнение операции и отправить полный запрос, включая данные в теле сообщения.The client application can then proceed and send the complete request including the data in the message body.

Если служба размещается с помощью служб IIS, драйвер HTTP.sys автоматически обнаруживает и обрабатывает заголовки Expect: 100-Continue перед передачей запросов в веб-приложение.If you are hosting a service by using IIS, the HTTP.sys driver automatically detects and handles Expect: 100-Continue headers before passing requests to your web application. Это означает, что существует небольшая вероятность увидеть эти заголовки в коде приложения, и можно предположить, что IIS уже отсортировали любые сообщения, которые они посчитали неподходящими или слишком большими.This means that you are unlikely to see these headers in your application code, and you can assume that IIS has already filtered any messages that it deems to be unfit or too large.

Если вы создаете клиентские приложения с помощью .NET Framework, то все сообщения POST и PUT по умолчанию сначала будут отправлять сообщения с заголовком Expect: 100-Continue по умолчанию.If you are building client applications by using the .NET Framework, then all POST and PUT messages will first send messages with Expect: 100-Continue headers by default. Так же, как и на стороне сервера, этот процесс обрабатывается прозрачно платформой .NET Framework.As with the server-side, the process is handled transparently by the .NET Framework. Однако этот процесс приводит к тому, что каждый запрос POST и PUT проходит два цикла обработки на сервере, даже если запрос небольшой.However, this process results in each POST and PUT request causing two round-trips to the server, even for small requests. Если приложение не отправляет запросы с большими объемами данных, можно отключить эту функцию с помощью класса ServicePointManager для создания объектов ServicePoint в клиентском приложении.If your application is not sending requests with large amounts of data, you can disable this feature by using the ServicePointManager class to create ServicePoint objects in the client application. Объект ServicePoint обрабатывает соединение, которое клиент устанавливает с сервером, на основе схемы и фрагментов узла из кодов URI, которые определяют ресурсы на сервере.A ServicePoint object handles the connections that the client makes to a server based on the scheme and host fragments of URIs that identify resources on the server. Затем можно присвоить свойству Expect100Continue объекта ServicePoint значение false.You can then set the Expect100Continue property of the ServicePoint object to false. Все последующие запросы POST и PUT, сделанные клиентом через URI, который соответствует схеме и фрагментам узла объекта ServicePoint, будут отправляться без заголовков Expect: 100-Continue.All subsequent POST and PUT requests made by the client through a URI that matches the scheme and host fragments of the ServicePoint object will be sent without Expect: 100-Continue headers. В примере кода ниже показано, как настроить объект ServicePoint, который настраивает все запросы, отправленные на URI со схемой http и узлом www.contoso.com.The following code shows how to configure a ServicePoint object that configures all requests sent to URIs with a scheme of http and a host of www.contoso.com.

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

Можно также задать статическое Expect100Continue свойство ServicePointManager класс, чтобы указать значение этого свойства по умолчанию для всех создаваемых в последующем ServicePoint объектов.You can also set the static Expect100Continue property of the ServicePointManager class to specify the default value of this property for all subsequently created ServicePoint objects.

Поддержка разбиения на страницы для запросов, которые могут возвращать большое количество объектовSupport pagination for requests that may return large numbers of objects

Если коллекция содержит большое количество ресурсов, отправка запроса GET на соответствующий URI может привести значительной обработки на сервере, на котором размещен веб-API, что влияет на производительность и создает значительный объем сетевого трафика. В свою очередь это приводит к увеличению времени задержки.If a collection contains a large number of resources, issuing a GET request to the corresponding URI could result in significant processing on the server hosting the web API affecting performance, and generate a significant amount of network traffic resulting in increased latency.

В таких случаях веб-API должен поддерживать строки запроса, которые позволяют клиентскому приложению уточнять запросы или делать выборку данных в виде более управляемых, отдельных блоках (или страницах).To handle these cases, the web API should support query strings that enable the client application to refine requests or fetch data in more manageable, discrete blocks (or pages). В примере кода ниже показан метод GetAllOrders контроллера Orders.The code below shows the GetAllOrders method in the Orders controller. Этот метод получает сведения о заказах.This method retrieves the details of orders. В случае отсутствия ограничений он может возвратить большой объем данных.If this method was unconstrained, it could conceivably return a large amount of data. Параметры limit и offset предназначены для сокращения объема данных до небольшого подмножества, в этом случае — только первые 10 заказов по умолчанию:The limit and offset parameters are intended to reduce the volume of data to a smaller subset, in this case only the first 10 orders by default:

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

Клиентское приложение может выдать запрос на получение 30 заказов, начиная с позиции смещения 50, используя такой URI: https://www.adventure-works.com/api/orders?limit=30&offset=50.A client application can issue a request to retrieve 30 orders starting at offset 50 by using the URI https://www.adventure-works.com/api/orders?limit=30&offset=50.

Совет

Избегайте предоставления клиентским приложениям возможности задавать строки запроса, которые приводят к созданию URI длиной более 2000 символов.Avoid enabling client applications to specify query strings that result in a URI that is more than 2000 characters long. Многие веб-клиенты и серверы не в состоянии обработать URI такой длины.Many web clients and servers cannot handle URIs that are this long.

Обеспечение доступности, масштабируемости и скорости реагированияMaintaining responsiveness, scalability, and availability

Один и тот же веб-API может использоваться несколькими клиентскими приложениями, работающими в любой точке мира.The same web API might be used by many client applications running anywhere in the world. Очень важно убедиться, что веб-API реализован так, что обеспечивает одинаковую скорость реагирования при интенсивной нагрузке, масштабируемость для поддержки непостоянной рабочей нагрузки, а также гарантирует доступность для клиентов, выполняющих критически важные бизнес-операции.It is important to ensure that the web API is implemented to maintain responsiveness under a heavy load, to be scalable to support a highly varying workload, and to guarantee availability for clients that perform business-critical operations. При определении того, как обеспечить соответствие этим требованиям, необходимо учитывать указанные ниже моменты.Consider the following points when determining how to meet these requirements:

Поддержка асинхронных операций для длительных запросовProvide asynchronous support for long-running requests

Запрос, обработка которого может занять много времени, следует выполнять без блокирования клиента, отправившего этот запрос.A request that might take a long time to process should be performed without blocking the client that submitted the request. Веб-API может выполнить некоторую начальную проверку запроса, инициировать отдельную задачу для выполнения работы, а затем вернуть ответное сообщение с кодом HTTP 202 (принято).The web API can perform some initial checking to validate the request, initiate a separate task to perform the work, and then return a response message with HTTP code 202 (Accepted). Такую задачу можно обработать асинхронно в самой службе веб-API или передать на выполнение в фоновый процесс.The task could run asynchronously as part of the web API processing, or it could be offloaded to a background task.

В веб-API также должен быть реализован механизм для возвращения результатов обработки обратно в клиентское приложение.The web API should also provide a mechanism to return the results of the processing to the client application. Добиться этого можно за счет предоставления механизма опроса для клиентских приложений с целью периодически запрашивать у них сведения о завершении обработки и получить результат. Либо веб-API можно настроить на отправку уведомлений по завершении операции.You can achieve this by providing a polling mechanism for client applications to periodically query whether the processing has finished and obtain the result, or enabling the web API to send a notification when the operation has completed.

Реализовать простой механизм опроса можно, предоставив URI polling (действует как виртуальный ресурс) в рамках следующего подхода.You can implement a simple polling mechanism by providing a polling URI that acts as a virtual resource using the following approach:

  1. Клиентское приложение отправляет первоначальный запрос в веб-API.The client application sends the initial request to the web API.
  2. Веб-API сохраняет сведения о запросе в таблице, находящейся в хранилище таблиц или в кэше Microsoft Azure, и генерирует уникальный ключ для этой записи, возможно, в виде идентификатора GUID.The web API stores information about the request in a table held in table storage or Microsoft Azure Cache, and generates a unique key for this entry, possibly in the form of a GUID.
  3. Веб-API инициирует обработку в рамках отдельной задачи.The web API initiates the processing as a separate task. Веб-API записывает состояние задачи в таблице как Running.The web API records the state of the task in the table as Running.
  4. Веб-API возвращает ответное сообщение с кодом состояния HTTP 202 (принято) и идентификатором GUID записи в таблице в теле сообщения.The web API returns a response message with HTTP status code 202 (Accepted), and the GUID of the table entry in the body of the message.
  5. После завершения задачи веб-API сохраняет результаты в таблице, определяя для задачи состояние Complete.When the task has completed, the web API stores the results in the table, and sets the state of the task to Complete. Обратите внимание: если задача завершается сбоем, веб-API может сохранить сведения об ошибке и установить состояние Failed.Note that if the task fails, the web API could also store information about the failure and set the status to Failed.
  6. Пока выполняется задача, клиент может продолжать выполнять собственную обработку.While the task is running, the client can continue performing its own processing. Он может периодически отправлять запрос к URI /polling/{guid} где {guid}  — это идентификатор GUID, возвращаемый веб-API в ответном сообщении с кодом 202.It can periodically send a request to the URI /polling/{guid} where {guid} is the GUID returned in the 202 response message by the web API.
  7. Веб-API с URI /polling/{guid} запрашивает состояние соответствующей задачи в таблице и возвращает ответное сообщение с кодом HTTP 200 ("ОК"), которое и содержит это состояние (Running, Complete или Failed).The web API at the /polling/{guid} URI queries the state of the corresponding task in the table and returns a response message with HTTP status code 200 (OK) containing this state (Running, Complete, or Failed). Если задача завершена успешно или с ошибкой, ответное сообщение также может включать результаты обработки или любые доступные сведения о причине сбоя.If the task has completed or failed, the response message can also include the results of the processing or any information available about the reason for the failure.

Ниже описаны несколько возможных вариантов для реализации уведомлений.Options for implementing notifications include:

  • Используя Центр уведомлений для отправки асинхронных ответов клиентским приложениям.Using a notification hub to push asynchronous responses to client applications. Дополнительные сведения см. в разделе отправлять уведомления конкретным пользователям с помощью центров уведомлений Azure.For more information, see Send notifications to specific users by using Azure Notification Hubs.
  • Использование модели Comet для сохранения постоянного сетевого соединения между клиентом и сервером, на котором размещен веб-API, и использование этого подключения для отправки сообщения от сервера обратно клиенту.Using the Comet model to retain a persistent network connection between the client and the server hosting the web API, and using this connection to push messages from the server back to the client. В статье Создание простого Comet-приложения в Microsoft .NET Framework в журнале MSDN описывается пример решения.The MSDN magazine article Building a Simple Comet Application in the Microsoft .NET Framework describes an example solution.
  • Использование SignalR для отправки данных в режиме реального времени с веб-сервера клиенту через постоянное сетевое подключение.Using SignalR to push data in real time from the web server to the client over a persistent network connection. SignalR доступен для веб-приложений ASP.NET в виде пакета NuGet.SignalR is available for ASP.NET web applications as a NuGet package. Дополнительные сведения см.на веб-сайте ASP.NET SignalR .You can find more information on the ASP.NET SignalR website.

Реализация всех запросов без учета состоянияEnsure that each request is stateless

Каждый запрос следует считать атомарным.Each request should be considered atomic. Должны отсутствовать зависимости между одним запросом от клиентского приложения и всеми последующими запросами, отправленными от того же клиента.There should be no dependencies between one request made by a client application and any subsequent requests submitted by the same client. Такой подход способствует масштабируемости; экземпляры веб-службы можно развернуть на нескольких серверах.This approach assists in scalability; instances of the web service can be deployed on a number of servers. Клиентские запросы можно направить в любой из этих экземпляров, и результаты при этом всегда должны быть одинаковыми.Client requests can be directed at any of these instances and the results should always be the same. По этой же причине повышается и доступность; в случае сбоя веб-сервера запросы можно передать в другой экземпляр (с помощью диспетчера трафика Azure), пока сервер перезапускается, что не оказывает никакого влияния на клиентские приложения.It also improves availability for a similar reason; if a web server fails requests can be routed to another instance (by using Azure Traffic Manager) while the server is restarted with no ill effects on client applications.

Отслеживание клиентов и поддержка регулирования, которые позволяют снизить вероятность DOS-атакTrack clients and implement throttling to reduce the chances of DOS attacks

Если определенный клиент выполняет большое количество запросов в течение заданного периода времени, он может монополизировать службу и повлиять на производительность других клиентов.If a specific client makes a large number of requests within a given period of time it might monopolize the service and affect the performance of other clients. Чтобы устранить эту проблему, веб-API может отслеживать вызовы от клиентских приложений с помощью отслеживания IP-адреса для всех входящих запросов или путем регистрации в журнале каждой операции доступа с проверкой подлинности.To mitigate this issue, a web API can monitor calls from client applications either by tracking the IP address of all incoming requests or by logging each authenticated access. Эти сведения можно использовать для ограничения доступа к ресурсам.You can use this information to limit resource access. Если клиент превышает заданный предел, веб-API может вернуть ответное сообщение с состоянием 503 (служба недоступна) и включить заголовок Retry-After, указывающий, когда клиент сможет отправить следующий запрос, который не будет отклонен.If a client exceeds a defined limit, the web API can return a response message with status 503 (Service Unavailable) and include a Retry-After header that specifies when the client can send the next request without it being declined. Эта стратегия помогает снизить вероятность атак типа "отказ в обслуживании" от ряда клиентов, замедляющих работу системы.This strategy can help to reduce the chances of a Denial Of Service (DOS) attack from a set of clients stalling the system.

Осторожность при управлении постоянными HTTP-подключениямиManage persistent HTTP connections carefully

Протокол HTTP поддерживает постоянные HTTP-подключения, где они доступны.The HTTP protocol supports persistent HTTP connections where they are available. В спецификации HTTP 1.0 добавлены Connection: Keep-Alive заголовок, который позволяет клиентскому приложению указать серверу, его можно использовать то же подключение для отправки последующих запросов, а не открывать новые сеансы.The HTTP 1.0 specification added the Connection:Keep-Alive header that enables a client application to indicate to the server that it can use the same connection to send subsequent requests rather than opening new ones. Подключение закрывается автоматически, если клиент не использовал подключение повторно в течение промежутка времени, определенного узлом.The connection closes automatically if the client does not reuse the connection within a period defined by the host. Это поведение применяется по умолчанию в HTTP 1.1 и используется службами Azure, поэтому нет необходимости включать в сообщения заголовки Keep-Alive.This behavior is the default in HTTP 1.1 as used by Azure services, so there is no need to include Keep-Alive headers in messages.

Постоянно открытое подключение может помочь повысить скорость реагирования за счет снижения задержки и перегрузки сети, однако это может помешать масштабируемости, так как остается больше открытых подключений, чем требуется, а это ограничивает возможность параллельного подключения других клиентов.Keeping a connection open can help to improve responsiveness by reducing latency and network congestion, but it can be detrimental to scalability by keeping unnecessary connections open for longer than required, limiting the ability of other concurrent clients to connect. Это также может повлиять на время работы от батареи, если клиентское приложение выполняется на мобильном устройстве; если приложение выполняет лишь редкие запросы к серверу, постоянно открытое подключение может привести к более быстрому разряду батареи.It can also affect battery life if the client application is running on a mobile device; if the application only makes occasional requests to the server, maintaining an open connection can cause the battery to drain more quickly. Для указания того, чтобы подключение по HTTP 1.1 не было постоянным, клиент может включить в сообщения заголовок Connection:Close. Это позволит переопределить поведение по умолчанию.To ensure that a connection is not made persistent with HTTP 1.1, the client can include a Connection:Close header with messages to override the default behavior. Аналогично, если сервер обрабатывает большое количество клиентов, он может включить в ответные сообщения заголовок Connection:Close, что позволяет закрыть подключение и сэкономить ресурсы сервера.Similarly, if a server is handling a very large number of clients it can include a Connection:Close header in response messages which should close the connection and save server resources.

Примечание

Постоянные HTTP-подключения абсолютно необязательны. Они призваны уменьшить нагрузку на сеть, связанную с многократным установлением канала связи.Persistent HTTP connections are a purely optional feature to reduce the network overhead associated with repeatedly establishing a communications channel. Ни веб-API, ни клиентское приложение не должно зависеть от постоянного HTTP-подключения, которое доступно.Neither the web API nor the client application should depend on a persistent HTTP connection being available. Не используйте постоянные HTTP-подключения для реализации систем уведомлений стиле Comet; Вместо этого следует использовать сокеты (или websockets, если он доступен) на уровне TCP.Do not use persistent HTTP connections to implement Comet-style notification systems; instead you should use sockets (or websockets if available) at the TCP layer. Наконец, обратите внимание, что возможности использования заголовков Keep-Alive ограничены, если клиентское приложение подключается к серверу через прокси-сервер; постоянным в этом случае будет только соединение между клиентом и прокси-сервером.Finally, note Keep-Alive headers are of limited use if a client application communicates with a server via a proxy; only the connection with the client and the proxy will be persistent.

Публикация веб-API и управление имPublishing and managing a web API

Чтобы сделать веб-API доступным для клиентских приложений, веб-API следует развернуть в среде узла.To make a web API available for client applications, the web API must be deployed to a host environment. Такой средой обычно является веб-сервер, хотя это может быть и другой тип хост-процесса.This environment is typically a web server, although it may be some other type of host process. При публикации веб-API следует учитывать следующие моменты.You should consider the following points when publishing a web API:

  • Все запросы должны пройти проверку подлинности и авторизацию, а также необходимо обеспечить соответствующий уровень контроля доступа.All requests must be authenticated and authorized, and the appropriate level of access control must be enforced.
  • В отношении коммерческого веб-API могут применяться различные гарантии качества, касающиеся времени ответа.A commercial web API might be subject to various quality guarantees concerning response times. Очень важно убедиться, что среда размещения является масштабируемой, если со временем нагрузка может значительно меняться.It is important to ensure that host environment is scalable if the load can vary significantly over time.
  • Возможно, запросы потребуется отслеживать для целей тарификации.It may be necessary to meter requests for monetization purposes.
  • Может потребоваться направлять поток трафика веб-API, а также реализовать регулирование для определенных клиентов, исчерпавших свои квоты.It might be necessary to regulate the flow of traffic to the web API, and implement throttling for specific clients that have exhausted their quotas.
  • Согласно нормативным требованиям может оказаться обязательным вести журнал и аудит всех запросов и ответов.Regulatory requirements might mandate logging and auditing of all requests and responses.
  • Чтобы обеспечить доступность, может потребоваться отслеживать работоспособностью сервера, на котором размещен веб-API, и при необходимости перезапускать сервер.To ensure availability, it may be necessary to monitor the health of the server hosting the web API and restart it if necessary.

Полезно иметь возможность отделять эти проблемы от технических проблем, касающихся реализации веб-API.It is useful to be able to decouple these issues from the technical issues concerning the implementation of the web API. По этой причине рассмотрите возможность создания оболочки, которая запущена как отдельный процесс и направляет запросы к веб-API.For this reason, consider creating a façade, running as a separate process and that routes requests to the web API. Оболочка может предоставить операции управления и переадресовывать проверенные запросы к веб-API.The façade can provide the management operations and forward validated requests to the web API. Использование оболочки обеспечивает множество функциональных преимуществ, включая приведенные ниже.Using a façade can also bring many functional advantages, including:

  • Выступает в качестве точки интеграции для нескольких веб-API.Acting as an integration point for multiple web APIs.
  • Преобразование сообщений и протоколов связи для клиентов, созданных с использованием различных технологий.Transforming messages and translating communications protocols for clients built by using varying technologies.
  • Кэширование запросов и ответов для снижения нагрузки на сервер, на котором размещен веб-API.Caching requests and responses to reduce load on the server hosting the web API.

Тестирование веб-APITesting a web API

Веб-API следует тестировать так же тщательно, как и любой другой компонент программного обеспечения.A web API should be tested as thoroughly as any other piece of software. Рекомендуется создать модульные тесты для проверки работы операций.You should consider creating unit tests to validate the functionality.

Характер веб-API привносит свои определенные требования к проверке правильности его работы.The nature of a web API brings its own additional requirements to verify that it operates correctly. Следует уделять особое внимание указанным ниже моментам.You should pay particular attention to the following aspects:

  • Проверьте все маршруты и убедитесь, что они вызывают все необходимые операции.Test all routes to verify that they invoke the correct operations. Особое внимание следует уделять коду состояния HTTP 405 (метод запрещен), который может быть неожиданно возвращен, поскольку это может означать несоответствие маршрута и методов HTTP (GET, POST, PUT, DELETE), которые можно передавать по этому маршруту.Be especially aware of HTTP status code 405 (Method Not Allowed) being returned unexpectedly as this can indicate a mismatch between a route and the HTTP methods (GET, POST, PUT, DELETE) that can be dispatched to that route.

    Отправляйте HTTP-запросы по маршрутам, которые их не поддерживают (например, отправьте запрос POST к определенному ресурсу [запросы POST должны отправляться только к коллекции ресурсов]).Send HTTP requests to routes that do not support them, such as submitting a POST request to a specific resource (POST requests should only be sent to resource collections). В этих случаях единственным допустимым ответом должен быть код состояния 405 ("Запрещено").In these cases, the only valid response should be status code 405 (Not Allowed).

  • Убедитесь, что все маршруты защищены надлежащим образом и используют необходимые процедуры проверки подлинности и авторизации.Verify that all routes are protected properly and are subject to the appropriate authentication and authorization checks.

    Примечание

    Некоторые аспекты безопасности, такие как проверка подлинности пользователя, вероятнее всего реализуются средой размещения, а не веб-API, однако вам по-прежнему необходимо включить в процесс развертывания тесты безопасности.Some aspects of security such as user authentication are most likely to be the responsibility of the host environment rather than the web API, but it is still necessary to include security tests as part of the deployment process.

  • Проверьте обработку исключений, выполняемую каждой операцией, и убедитесь, что в клиентское приложение обратно передается соответствующий и значимый ответ HTTP.Test the exception handling performed by each operation and verify that an appropriate and meaningful HTTP response is passed back to the client application.

  • Убедитесь, что запросы и ответные сообщения имеют правильный формат.Verify that request and response messages are well-formed. Например, если запрос HTTP POST содержит данные для нового ресурса в формате x-www-form-urlencoded, убедитесь, что соответствующая операция правильно анализирует данные, создает ресурсы и возвращает ответ, содержащий сведения о новом ресурсе, включая правильный заголовок Location.For example, if an HTTP POST request contains the data for a new resource in x-www-form-urlencoded format, confirm that the corresponding operation correctly parses the data, creates the resources, and returns a response containing the details of the new resource, including the correct Location header.

  • Проверяйте все ссылки и URI в ответных сообщениях.Verify all links and URIs in response messages. Например сообщения HTTP POST должен возвращаться URI вновь созданного ресурса.For example, an HTTP POST message should return the URI of the newly created resource. Все ссылки HATEOAS должно быть действительными.All HATEOAS links should be valid.

  • Убедитесь, что каждая операция возвращает правильные коды состояния для различных сочетаний входных данных.Ensure that each operation returns the correct status codes for different combinations of input. Пример:For example:

    • Если запрос выполнен успешно, она должна возвращать код состояния 200 (ОК)If a query is successful, it should return status code 200 (OK)
    • Если ресурс не найден, то операция должна возвращать код состояния HTTP "404 (не найдено)".If a resource is not found, the operation should return HTTP status code 404 (Not Found).
    • Если клиент отправляет запрос, который успешно удаляет ресурс, код состояния должен быть 204 (нет содержимого).If the client sends a request that successfully deletes a resource, the status code should be 204 (No Content).
    • Если клиент отправляет запрос, который создает ресурс, код состояния должен быть 201 (создано).If the client sends a request that creates a new resource, the status code should be 201 (Created).

Следует внимательно отслеживать неожиданные ответы с кодами состояния в диапазоне 5xx.Watch out for unexpected response status codes in the 5xx range. Обычно эти сообщения отправляются сервером размещения для указания того, что ему не удалось выполнить допустимый запрос.These messages are usually reported by the host server to indicate that it was unable to fulfill a valid request.

  • Проверьте различные сочетания заголовков запроса, которые клиентское приложение может указывать, и убедитесь, что веб-API возвращает в ответных сообщениях ожидаемые данные.Test the different request header combinations that a client application can specify and ensure that the web API returns the expected information in response messages.

  • Проверьте строки запроса.Test query strings. Если операция может принимать необязательные параметры (такие как запросы разбивки на страницы), протестируйте различные комбинации параметров и порядок их указания.If an operation can take optional parameters (such as pagination requests), test the different combinations and order of parameters.

  • Убедитесь, что асинхронные операции завершаются успешно.Verify that asynchronous operations complete successfully. Если веб-API поддерживает потоковую передачу запросов, которые возвращают большие двоичные объекты (например, видео или аудио), убедитесь, что клиентские запросы не блокируются во время потоковой передачи данных.If the web API supports streaming for requests that return large binary objects (such as video or audio), ensure that client requests are not blocked while the data is streamed. Если веб-API реализует опрос для операций модификации данных выполняющейся длительное время, убедитесь, что операции сообщают о своем состоянии надлежащим образом.If the web API implements polling for long-running data modification operations, verify that the operations report their status correctly as they proceed.

Необходимо также создать и запустить тесты производительности для проверки того, что веб-API работает удовлетворительно в принудительном режиме.You should also create and run performance tests to check that the web API operates satisfactorily under duress. С помощью Visual Studio Ultimate можно создать проект нагрузочного теста и веб-теста производительности.You can build a web performance and load test project by using Visual Studio Ultimate. Дополнительные сведения см. в статье о тестах производительности перед выпуском приложения.For more information, see Run performance tests on an application before a release.

Использование управления API AzureUsing Azure API Management

В Azure, рассмотрите возможность использования управления API Azure для публикации и управления веб-API.On Azure, consider using Azure API Management to publish and manage a web API. С помощью этого средства вы можете создать службу, которая выступает в роли оболочки для одного или нескольких веб-API.Using this facility, you can generate a service that acts as a façade for one or more web APIs. Сама служба представляет масштабируемые веб-службы, можно создать и настроить с помощью портала Azure.The service is itself a scalable web service that you can create and configure by using the Azure portal. Эту службу можно использовать для публикации и управления веб-API, как указано ниже.You can use this service to publish and manage a web API as follows:

  1. Разверните веб-API для веб-сайта, облачной службы Azure или виртуальной машины Azure.Deploy the web API to a website, Azure cloud service, or Azure virtual machine.

  2. Подключите службу управления API к веб-API.Connect the API management service to the web API. Запросы, отправленные на URL-адрес API управления, сопоставляются с URI в веб-API.Requests sent to the URL of the management API are mapped to URIs in the web API. Эта же служба управления API может направить запросы в несколько веб-API.The same API management service can route requests to more than one web API. Это позволяет объединить несколько веб-API в рамках одной службы управления.This enables you to aggregate multiple web APIs into a single management service. Аналогичным образом, на один и тот же веб-API можно ссылаться из нескольких служб управления API, если необходимо ограничить или разделить функциональные возможности, доступные для различных приложений.Similarly, the same web API can be referenced from more than one API management service if you need to restrict or partition the functionality available to different applications.

    Примечание

    URI в ссылках HATEOAS, созданных в ответе на запросы HTTP GET, должны ссылаться на URL-адрес службы управления API, а не на веб-сервер, на котором размещен веб-API.The URIs in HATEOAS links generated as part of the response for HTTP GET requests should reference the URL of the API management service and not the web server hosting the web API.

  3. Для каждого веб-API укажите операции HTTP, предоставляемые веб-API вместе с любыми дополнительными параметрами, которые операция может принимать в качестве входных.For each web API, specify the HTTP operations that the web API exposes together with any optional parameters that an operation can take as input. Можно также указать, следует ли службе управления API кэшировать ответ, полученный от веб-API, для оптимизации повторных запросов тех же данных.You can also configure whether the API management service should cache the response received from the web API to optimize repeated requests for the same data. Запишите сведения об ответах HTTP, которые может создавать каждая операция.Record the details of the HTTP responses that each operation can generate. Эта информация используется для создания документации для разработчиков, поэтому важно, чтобы она была точной и полной.This information is used to generate documentation for developers, so it is important that it is accurate and complete.

    Вы можете определить операций вручную с помощью мастеров, имеющихся на портале Azure, или их можно импортировать из файла, содержащего определения в формате WADL или Swagger.You can either define operations manually using the wizards provided by the Azure portal, or you can import them from a file containing the definitions in WADL or Swagger format.

  4. Настройте параметры безопасности для взаимодействия службы управления API с веб-сервером, на котором размещен веб-API.Configure the security settings for communications between the API management service and the web server hosting the web API. Служба управления API в настоящее время поддерживает обычную проверку подлинности и взаимную проверку подлинности с использованием сертификатов, а также проверку подлинности пользователей OAuth 2.0.The API management service currently supports Basic authentication and mutual authentication using certificates, and OAuth 2.0 user authorization.

  5. Создайте продукт.Create a product. Продукт — это единица публикации; можно добавить веб-API, ранее подключенные вами к службе управления для продукта.A product is the unit of publication; you add the web APIs that you previously connected to the management service to the product. После публикации продукта веб-API становятся доступными для разработчиков.When the product is published, the web APIs become available to developers.

    Примечание

    Перед публикацией продукта можно также определить группы пользователей, которые могут получить доступ к продукту, и добавить пользователей в эти группы.Prior to publishing a product, you can also define user-groups that can access the product and add users to these groups. Это позволит вам получить контроль над разработчиками и приложениями, использующими веб-API.This gives you control over the developers and applications that can use the web API. Если веб-API необходимо утвердить, то прежде чем получить доступ к нему разработчик должен отправить запрос администратору продукта.If a web API is subject to approval, prior to being able to access it a developer must send a request to the product administrator. Администратор может предоставить или запретить доступ для разработчика.The administrator can grant or deny access to the developer. В случае если обстоятельства изменились, можно также заблокировать существующих разработчиков.Existing developers can also be blocked if circumstances change.

  6. Настройте политики для каждого веб-API.Configure policies for each web API. Политики управляют такими аспектами, как выполнение междоменных вызовов, способ проверки подлинности клиентов, выполнение прозрачного преобразования между форматами данных XML и JSON, ограничение вызовов из заданного диапазона IP-адресов, квоты на использование, а также ограничение скорости вызова.Policies govern aspects such as whether cross-domain calls should be allowed, how to authenticate clients, whether to convert between XML and JSON data formats transparently, whether to restrict calls from a given IP range, usage quotas, and whether to limit the call rate. Политики могут применяться глобально для всего продукта, для одного веб-API в продукте или для отдельных операций в веб-API.Policies can be applied globally across the entire product, for a single web API in a product, or for individual operations in a web API.

Дополнительные сведения см. в разделе документация по службе управления API.For more information, see the API Management documentation.

Совет

Azure предоставляет диспетчер трафика Azure, который позволяет реализовать отказоустойчивость и балансировку нагрузки, а также уменьшить задержку между несколькими экземплярами веб-сайта, размещенного в различных географических регионах.Azure provides the Azure Traffic Manager which enables you to implement failover and load-balancing, and reduce latency across multiple instances of a web site hosted in different geographic locations. Диспетчер трафика Azure можно использовать в сочетании со службой управления API; последняя может направлять запросы в экземпляры веб-сайта через диспетчер трафика Azure.You can use Azure Traffic Manager in conjunction with the API Management Service; the API Management Service can route requests to instances of a web site through Azure Traffic Manager. Дополнительные сведения см. в статье Методы маршрутизации трафика диспетчером трафика.For more information, see Traffic Manager routing methods.

В этой структуре при использовании пользовательских DNS-имен для веб-сайтов необходимо настроить соответствующую запись CNAME для каждого веб-сайта, которая должна указывать на DNS-имя веб-сайта диспетчера трафика Azure.In this structure, if you are using custom DNS names for your web sites, you should configure the appropriate CNAME record for each web site to point to the DNS name of the Azure Traffic Manager web site.

Поддержка разработчиков на стороне клиентаSupporting client-side developers

Для разработчиков, занимающихся созданием клиентских приложений, обычно требуются сведения о том, как получить доступ к веб-API, и документация, касающаяся параметров, типов данных, возвращаемых типов и кодов возврата, которые описывают различные запросы и ответы между веб-службой и клиентским приложением.Developers constructing client applications typically require information on how to access the web API, and documentation concerning the parameters, data types, return types, and return codes that describe the different requests and responses between the web service and the client application.

Документирование операций REST для веб-APIDocument the REST operations for a web API

В состав службы управления API Azure входит портал для разработчиков, на котором представлены описания операций REST, предоставляемых веб-API.The Azure API Management Service includes a developer portal that describes the REST operations exposed by a web API. Если продукт был опубликован, он отображается на этом портале.When a product has been published it appears on this portal. Разработчики могут использовать этот портал для регистрации доступа; после чего администратор может утвердить или отклонить запрос.Developers can use this portal to sign up for access; the administrator can then approve or deny the request. Если разработчик утвержден, ему назначается ключ подписки, который используется для проверки подлинности вызовов из разрабатываемых им клиентских приложений.If the developer is approved, they are assigned a subscription key that is used to authenticate calls from the client applications that they develop. Этот ключ необходимо предоставлять при каждом вызове веб-API, в противном случае вызов будет отклонен.This key must be provided with each web API call otherwise it will be rejected.

На этом портале также предоставлено следующее:This portal also provides:

  • документация по продукту, список операций, которые он предоставляет, необходимые параметры и разные ответы, которые могут быть возвращены;Documentation for the product, listing the operations that it exposes, the parameters required, and the different responses that can be returned. обратите внимание, что эта информация основывается на данных, указанных на шаге 3 в списке в разделе "Публикация и управление веб-API с помощью службы управления API Azure";Note that this information is generated from the details provided in step 3 in the list in the Publishing a web API by using the Microsoft Azure API Management Service section.
  • фрагменты кода, которые показывают, как вызывать операции на нескольких языках программирования, включая JavaScript, C#, Java, Ruby, Python и PHP;Code snippets that show how to invoke operations from several languages, including JavaScript, C#, Java, Ruby, Python, and PHP.
  • консоль разработчика, с помощью которой разработчики могут отправлять запрос HTTP для проверки каждой операции в продукте и просмотра результатов;A developers' console that enables a developer to send an HTTP request to test each operation in the product and view the results.
  • страница, где разработчик может сообщить об обнаруженных ошибках и проблемах.A page where the developer can report any issues or problems found.

Портал Azure позволяет настраивать на портале разработчика, чтобы изменить стиль оформления и макет с учетом фирменной символики организации.The Azure portal enables you to customize the developer portal to change the styling and layout to match the branding of your organization.

Реализация клиентского пакета SDKImplement a client SDK

Для создания клиентского приложения, которое вызывает запросы REST на доступ к веб-API, требуется значительный объем кода для написания каждого запроса и форматирования его соответствующим образом, отправки запроса на сервер, на котором размещена веб-службы, синтаксического анализа ответа, вычисляющего то, успешно ли был выполнен запрос или завершился сбоем, а также извлечения всех возвращенных данных.Building a client application that invokes REST requests to access a web API requires writing a significant amount of code to construct each request and format it appropriately, send the request to the server hosting the web service, and parse the response to work out whether the request succeeded or failed and extract any data returned. Чтобы исключить в клиентском приложении эти проблемы, можно предоставить пакет SDK, который служит оболочкой для интерфейса REST и абстрагирует эти низкоуровневые элементы внутри более функционального набора методов.To insulate the client application from these concerns, you can provide an SDK that wraps the REST interface and abstracts these low-level details inside a more functional set of methods. Клиентское приложение использует эти методы, которые прозрачно преобразовывают вызовы в запросы REST, а ответы — обратно в возвращаемые методом значения.A client application uses these methods, which transparently convert calls into REST requests and then convert the responses back into method return values. Это распространенный метод, реализуемый многими службами, включая пакет Azure SDK.This is a common technique that is implemented by many services, including the Azure SDK.

Создание клиентского пакета SDK — довольно сложная задача, поскольку его следует согласованно и тщательно реализовывать и тестировать.Creating a client-side SDK is a considerable undertaking as it has to be implemented consistently and tested carefully. Однако большая часть этого процесса может выполняться механически, а многие поставщики предлагают средства, позволяющие автоматизировать выполнение многих из этих задач.However, much of this process can be made mechanical, and many vendors supply tools that can automate many of these tasks.

Наблюдение за веб-APIMonitoring a web API

В зависимости от способа публикации и развертывания веб-API можно отслеживать веб-API напрямую или организовать сбор сведений об использовании и работоспособности путем анализа трафика, проходящего через службу управления API.Depending on how you have published and deployed your web API you can monitor the web API directly, or you can gather usage and health information by analyzing the traffic that passes through the API Management service.

Наблюдение за веб-API напрямуюMonitoring a web API directly

При реализации веб-API с помощью шаблона веб-API ASP.NET (либо в качестве проекта веб-API, либо в виде веб-роли в облачной службе Azure) и Visual Studio 2013 вы можете организовать сбор данных о доступности, производительности и использовании данных с помощью ASP.NET Application Insights.If you have implemented your web API by using the ASP.NET Web API template (either as a Web API project or as a Web role in an Azure cloud service) and Visual Studio 2013, you can gather availability, performance, and usage data by using ASP.NET Application Insights. Application Insights — это пакет, который прозрачно отслеживает и записывает сведения о запросах и ответах, когда веб-API развернут в облаке. После установки и настройки пакета вам не нужно вносить изменения в код веб-API, чтобы использовать его.Application Insights is a package that transparently tracks and records information about requests and responses when the web API is deployed to the cloud; once the package is installed and configured, you don't need to amend any code in your web API to use it. При развертывании веб-API на веб-сайте Azure проверяется весь трафик, и собирается следующая статистика:When you deploy the web API to an Azure web site, all traffic is examined and the following statistics are gathered:

  • время ответа от сервера;Server response time.
  • число запросов к серверу и сведения о каждом запросе;Number of server requests and the details of each request.
  • самые медленные запросы по среднему времени ответа;The top slowest requests in terms of average response time.
  • сведения обо всех неудачных запросах;The details of any failed requests.
  • число сеансов, инициализированных в различных браузерах и различными агентами пользователя;The number of sessions initiated by different browsers and user agents.
  • наиболее часто просматриваемые страницы (в основном полезно для веб-приложений, а не для веб-API);The most frequently viewed pages (primarily useful for web applications rather than web APIs).
  • сведения о различных ролях пользователей, работающих с веб-API.The different user roles accessing the web API.

Эти данные можно просмотреть в режиме реального времени на портале Azure.You can view this data in real time in the Azure portal. Можно также создать веб-тесты, наблюдения за работоспособностью веб-API.You can also create web tests that monitor the health of the web API. В веб-тест периодически отправляет запрос на указанный URI в веб-API и записывает ответ.A web test sends a periodic request to a specified URI in the web API and captures the response. Можно указать определение успешного ответа (например, код состояния HTTP 200), и если запрос не возвращает этот ответ, можно настроить оповещение для отправки администратору.You can specify the definition of a successful response (such as HTTP status code 200), and if the request does not return this response you can arrange for an alert to be sent to an administrator. При необходимости администратор может перезапустить сервер, на котором размещен веб-API, если произошел сбой.If necessary, the administrator can restart the server hosting the web API if it has failed.

Дополнительные сведения см. в статье о начале работы с ASP.NET в Application Insights.For more information, see Application Insights - Get started with ASP.NET.

Наблюдение за веб-API через службу управления APIMonitoring a web API through the API Management Service

Если вы опубликовали веб-API с помощью службы управления API, на странице управления API на портале Azure содержит панель мониторинга, которая позволяет просматривать общую производительность службы.If you have published your web API by using the API Management service, the API Management page on the Azure portal contains a dashboard that enables you to view the overall performance of the service. На странице аналитики можно детализировать подробные сведения об использовании продукта.The Analytics page enables you to drill down into the details of how the product is being used. На этой странице представлены следующие вкладки:This page contains the following tabs:

  • Использование.Usage. На этой вкладке содержатся сведения о количестве вызовов API и пропускной способности, необходимой для обработки этих вызовов по времени.This tab provides information about the number of API calls made and the bandwidth used to handle these calls over time. Можно отфильтровать сведения об использовании по продуктам, API и операциям.You can filter usage details by product, API, and operation.
  • Работоспособность.Health. На этой вкладке вы можете просмотреть результаты запросов API (возвращенные коды состояния HTTP), сведения об эффективности политики кэширования, о времени ответа API и времени ответа службы.This tab enables you to view the outcome of API requests (the HTTP status codes returned), the effectiveness of the caching policy, the API response time, and the service response time. На этой вкладке можно так же фильтровать данные работоспособности по продуктам, API и операциям.Again, you can filter health data by product, API, and operation.
  • Действия.Activity. На этой вкладке представлена сводная информация в текстовом виде о количестве успешных вызовов, неудачных вызовов и заблокированных вызовов, о среднем времени отклика и времени отклика для каждого продукта, веб-API и каждой операции.This tab provides a text summary of the numbers of successful calls, failed calls, blocked calls, average response time, and response times for each product, web API, and operation. На этой странице также указано количество вызовов, совершенных каждым разработчиком.This page also lists the number of calls made by each developer.
  • Краткий обзор.At a glance. На этой вкладке представлена сводка по данным производительности, включая сведения о разработчиках, ответственных за совершение большинства вызовов API, а также информация о продуктах, веб-API и операциях, которые получили эти вызовы.This tab displays a summary of the performance data, including the developers responsible for making the most API calls, and the products, web APIs, and operations that received these calls.

Эти сведения можно использовать для определения того, является ли определенный веб-API или операция узким местом, чтобы при необходимости можно было масштабировать среду размещения и добавить дополнительные серверы.You can use this information to determine whether a particular web API or operation is causing a bottleneck, and if necessary scale the host environment and add more servers. Можно также получить представление о том, имеются ли приложения, которые используют неограниченный объем ресурсов, и применить соответствующие политики для установления квот и ограничений на скорость вызова.You can also ascertain whether one or more applications are using a disproportionate volume of resources and apply the appropriate policies to set quotas and limit call rates.

Примечание

Можно изменить данные для опубликованных продуктов. Изменения при этом вступают в силу сразу же.You can change the details for a published product, and the changes are applied immediately. Например, можно добавить или удалить операции из веб-API без необходимости повторной публикации продукта, который содержит этот веб-API.For example, you can add or remove an operation from a web API without requiring that you republish the product that contains the web API.

Дополнительные сведенияMore information