Patrón Static Content Hosting

Azure Storage

Implemente contenido estático en un servicio de almacenamiento basado en la nube que pueda entregarlo directamente al cliente. Así, puede reducir la necesidad de instancias de proceso potencialmente costosas.

Contexto y problema

Las aplicaciones web suelen incluyen algunos elementos de contenido estático. Este contenido estático puede incluir páginas HTML y otros recursos, como imágenes y documentos que están disponibles para el cliente, bien como parte de una página HTML (por ejemplo, imágenes en línea, hojas de estilos y archivos de JavaScript del lado cliente) o como descargas independientes (como documentos PDF).

Aunque los servidores web están optimizados para la representación dinámica y el almacenamiento en caché de los resultados, aun así deben gestionar las solicitudes para descargar contenido estático. Como consecuencia, se consumen ciclos de procesamiento que con frecuencia se podrían aprovecharse mejor.

Solución

En la mayoría de los entornos de hospedaje en la nube, puede colocar algunos de los recursos y páginas estáticas de una aplicación en un servicio de almacenamiento. El servicio de almacenamiento puede atender solicitudes de estos recursos, de forma que se reduce la carga en los recursos de proceso que gestionan otras solicitudes web. El costo de almacenamiento hospedado en la nube es normalmente mucho menor que para las instancias de proceso.

Al hospedar algunas partes de una aplicación en un servicio de almacenamiento, los principales aspectos que hay que tener en cuenta están relacionados con la implementación de la aplicación y la protección de los recursos que no están destinados a estar disponibles para usuarios anónimos.

Problemas y consideraciones

Tenga en cuenta los puntos siguientes al decidir cómo implementar este patrón:

  • El servicio de almacenamiento hospedado debe exponer un punto de conexión HTTP al que los usuarios puedan acceder para descargar los recursos estáticos. Algunos servicios de almacenamiento también admiten HTTPS, por lo que es posible hospedar los recursos en servicios de almacenamiento que requieran SSL.

  • Para obtener el máximo rendimiento y disponibilidad, considere la posibilidad de usar una red de entrega de contenido (CDN) para almacenar en caché el contenido del contenedor de almacenamiento en varios centros de datos por todo el mundo. Sin embargo, probablemente deba pagar por el uso de la red CDN.

  • Las cuentas de almacenamiento a menudo se replican geográficamente de forma predeterminada para proporcionar resistencia frente a eventos que podrían afectar a un centro de datos. Esto significa que la dirección IP podría cambiar, pero la dirección URL seguirá siendo la misma.

  • Cuando parte del contenido está ubicado en una cuenta de almacenamiento y otra parte en una instancia de proceso hospedada, se vuelve más difícil implementar y actualizar la aplicación. Es posible que deba realizar implementaciones independientes y controlar las versiones de la aplicación y el contenido para administrarlo de forma más fácil, en especial, cuando el contenido estático incluye archivos de script o componentes de interfaz de usuario. Sin embargo, si solo se tienen que actualizar recursos estáticos, pueden cargarse simplemente en la cuenta de almacenamiento sin necesidad de volver a implementar el paquete de aplicación.

  • Puede que los servicios de almacenamiento no admitan el uso de nombres de dominio personalizados. En este caso, es necesario especificar la dirección URL completa de los recursos en los vínculos ya que estarán en un dominio diferente al del contenido generado dinámicamente que incluye los vínculos.

  • Los contenedores de almacenamiento deben estar configurados para el acceso de lectura público, pero es esencial asegurarse de que no estén configurados para el acceso de escritura público para impedir que los usuarios puedan cargar contenido.

  • Considere la posibilidad de usar una clave de acceso limitado o un token para controlar el acceso a los recursos que no deben estar disponibles de forma anónima. Para más información, consulte el patrón Valet Key.

Cuándo usar este patrón

Este patrón es útil para:

  • Minimizar el costo de hospedaje de sitios web y aplicaciones que contienen algunos recursos estáticos.

  • Minimizar el costo de hospedaje de sitios web que solo constan de contenido y recursos estáticos. Según las funcionalidades del sistema de almacenamiento del proveedor de hospedaje, puede que exista la posibilidad de hospedar por completo un sitio web totalmente estático en una cuenta de almacenamiento.

  • Exponer recursos y contenido estáticos para aplicaciones que se ejecutan en otros entornos de hospedaje o en servidores locales.

  • Ubicar contenido en más de un área geográfica mediante una red de entrega de contenido que almacena en caché el contenido de la cuenta de almacenamiento en varios centros de datos por todo el mundo.

  • Supervisar los costos y el uso de ancho de banda. Usar una cuenta de almacenamiento independiente para todo el contenido estático o parte del mismo permite separar más fácilmente los costos de los costos de hospedaje y tiempo de ejecución.

Este patrón podría no ser útil en las siguientes situaciones:

  • La aplicación debe realizar algún procesamiento en el contenido estático antes de entregarlo al cliente. Por ejemplo, podría ser necesario agregar una marca de tiempo a un documento.

  • El volumen del contenido estático es muy pequeño. La sobrecarga que supone recuperar este contenido del almacenamiento independiente puede sobrepasar las ventajas en los costos de separarlo del recurso de proceso.

Diseño de cargas de trabajo

Un arquitecto debe evaluar cómo se puede usar el patrón Static Content Hosting en el diseño de su carga de trabajo para abordar los objetivos y principios descritos en los pilares del Marco de buena arquitectura de Azure. Por ejemplo:

Fundamento Cómo apoya este patrón los objetivos de los pilares
La optimización de costos se centra en mantener y mejorar el retorno de la inversión de la carga de trabajo. Los hosts de aplicaciones dinámicas suelen ser más caros que los hosts estáticos, ya que los hosts dinámicos pueden ejecutar la lógica de negocios codificada. El uso de una plataforma de aplicaciones para entregar contenido estático no es rentable.

- CO:09 Costos de flujo
- Co:10 Costos de datos
La eficiencia del rendimiento ayuda a que la carga de trabajo satisfaga eficazmente las demandas mediante optimizaciones en el escalado, los datos y el código. La descarga de la responsabilidad en un host externo ayuda a mitigar la congestión y le permite usar la plataforma de aplicaciones solo para ofrecer lógica de negocios.

- PE:07 Codificar una infraestructura

Al igual que con cualquier decisión de diseño, hay que tener en cuenta las ventajas y desventajas con respecto a los objetivos de los otros pilares que podrían introducirse con este patrón.

Ejemplo

Azure Storage admite el suministro de contenido estático directamente desde un contenedor de almacenamiento. Los archivos se proporcionan mediante solicitudes de acceso anónimo. De forma predeterminada, los archivos tienen una dirección URL en un subdominio de core.windows.net, como https://contoso.z4.web.core.windows.net/image.png. Puede configurar un nombre de dominio personalizado y usar Azure CDN para acceder a los archivos a través de HTTPS. Para más información, consulte Hospedaje de sitios web estáticos en Azure Storage.

Entrega de las partes estáticas de una aplicación directamente desde un servicio de almacenamiento

El hospedaje de sitios web estáticos permite que los archivos estén disponibles para el acceso anónimo. Si necesita controlar quién puede acceder a los archivos, puede almacenarlos en Azure Blob Storage y, luego, generar firmas de acceso compartido para limitar el acceso.

Los vínculos de las páginas entregadas al cliente deben especificar la dirección URL completa del recurso. Si el recurso está protegido con una clave de acceso limitado, como una firma de acceso compartido, esta firma debe incluirse en la dirección URL.

Se puede encontrar en GitHub una aplicación de ejemplo que muestra el uso de almacenamiento externo para recursos estáticos. En este ejemplo se usan archivos de configuración para especificar la cuenta de almacenamiento y el contenedor que alberga el contenido estático.

<Setting name="StaticContent.StorageConnectionString"
         value="UseDevelopmentStorage=true" />
<Setting name="StaticContent.Container" value="static-content" />

La clase Settings en el archivo Settings.cs del proyecto StaticContentHosting.Web contiene métodos para extraer estos valores y crear un valor de cadena que contiene la dirección URL del contenedor de la cuenta de almacenamiento en la nube.

public class Settings
{
  public static string StaticContentStorageConnectionString {
    get
    {
      return RoleEnvironment.GetConfigurationSettingValue(
                              "StaticContent.StorageConnectionString");
    }
  }

  public static string StaticContentContainer
  {
    get
    {
      return RoleEnvironment.GetConfigurationSettingValue("StaticContent.Container");
    }
  }

  public static string StaticContentBaseUrl
  {
    get
    {
        var blobServiceClient = new BlobServiceClient(StaticContentStorageConnectionString);

        return string.Format("{0}/{1}", blobServiceClient.Uri.ToString().TrimEnd('/'), StaticContentContainer.TrimStart('/'));
    }
  }
}

La clase StaticContentUrlHtmlHelper en el archivo StaticContentUrlHtmlHelper.cs expone un método denominado StaticContentUrl que genera una dirección URL que contiene la ruta de acceso a la cuenta de almacenamiento en la nube si la dirección URL pasada a esta comienza con el carácter de ruta de acceso raíz ASP.NET (~).

public static class StaticContentUrlHtmlHelper
{
  public static string StaticContentUrl(this HtmlHelper helper, string contentPath)
  {
    if (contentPath.StartsWith("~"))
    {
      contentPath = contentPath.Substring(1);
    }

    contentPath = string.Format("{0}/{1}", Settings.StaticContentBaseUrl.TrimEnd('/'),
                                contentPath.TrimStart('/'));

    var url = new UrlHelper(helper.ViewContext.RequestContext);

    return url.Content(contentPath);
  }
}

El archivo Index.cshtml de la carpeta Views\Home contiene un elemento de imagen que usa el método StaticContentUrl para crear la dirección URL de su atributo src.

<img src="@Html.StaticContentUrl("~/media/orderedList1.png")" alt="Test Image" />

Pasos siguientes

  • Patrón Valet Key. Si se supone que los recursos de destino no van a estar disponibles para usuarios anónimos, use este patrón para restringir el acceso directo.
  • Aplicación web sin servidor en Azure Una arquitectura de referencia que usa hospedaje de sitios web estáticos con Azure Functions para implementar una aplicación web sin servidor.