navigationend - Angular no actualiza la página con la memoria caché habilitada
title angular 6 (3)
Hice un sitio web angular que contiene un formulario "agregar" y un "eliminar" para manipular datos en una tabla en la misma página.
Cuando lo pruebo localmente o con Chrome Dev Console (caché desactivada), cuando agrego un nuevo elemento o lo elimino, la tabla se actualiza automáticamente. Cuando lo pruebo en el servidor de producción (servidor IIS) de mi cliente, solo funciona con la consola de desarrollo de Chrome abierta. De lo contrario, tienen que usar CTRL + F5 para actualizar el caché y mostrar los cambios en la página.
Este es el código de los componentes:
addProduct() {
this._productsService.addProduct(this.addFormProductItem)
.subscribe(v => {
this._productsService.getProducts().subscribe(
products => {this.products = products, this.onChangeTable(this.config)}
);
});
this.addmodalWindow.hide();
return;
}
onChangeTable(config: any, page: any = {
page: this.page,
itemsPerPage: this.itemsPerPage
}): any {
if (config.filtering) {
Object.assign(this.config.filtering, config.filtering);
}
if (config.sorting) {
Object.assign(this.config.sorting, config.sorting);
}
this.ng2TableData = this.products;
this.length = this.ng2TableData.length;
let filteredData = this.changeFilter(this.ng2TableData, this.config);
let sortedData = this.changeSort(filteredData, this.config);
this.rows = page && config.paging ? this.changePage(page, sortedData) : sortedData;
this.length = sortedData.length;
}
Supongo que está relacionado con alguna configuración del servidor o con el código del paquete web. Sin embargo, no estoy familiarizado con este último y lo dejé tal como estaba en el paquete inicial que utilicé.
Creé una esencia con el paquete web ya que es un archivo largo
Editar 1: después de algunas investigaciones adicionales, traté de agregar lo siguiente en un archivo web.config en la carpeta raíz de la aplicación.
<caching enabled="false" enableKernelCache="false">
<profiles>
<add extension=".css" policy="DontCache" kernelCachePolicy="DontCache" />
<add extension=".html" policy="DontCache" kernelCachePolicy="DontCache" />
<add extension=".js" policy="DontCache" kernelCachePolicy="DontCache" />
</profiles>
</caching>
Sin embargo, todavía tengo el mismo comportamiento. Al agregar un elemento con Dev Console cerrado, no actualiza la tabla. Pero si tengo la consola de desarrollo abierta e inhabilitó la memoria caché, entonces la actualiza sin necesidad de una actualización.
Editar 2: Trabajar en la ventana de incógnito no soluciona el problema.
Editar 3: Agregar metaetiquetas en index.html no soluciona el problema, nuevamente.
<meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
Editar 4:
getProducts() {
return this._http.get(this.API + ''/products/all'')
.map((response: Response) => <Product[]>response.json().products);
}
addProduct(product:Product) {
if ( this._loggedInGuard.isLoggedIn() ) {
let token = localStorage.getItem(''my.token'');
let body = JSON.stringify(product);
let headers = new Headers(
{ ''Content-Type'': ''application/json'',
''Authorization'': ''Bearer '' + token});
return this._http
.post(this.API + "/products/store", body, {headers: headers} )
.map(res => res.json())
.catch(this._responseService.catchBadResponse)
.do(() => this._responseService.success(''Success. You added a product!''));
}
}
Editar 5
La única solución que puedo encontrar es volver a cargar la ventana cada vez que realizo una actualización de datos con location.reload(true)
. Pero, de nuevo, esto solo funciona en Firefox y no en Chrome. Y no aceptaré que deba abandonar la única razón de tener una aplicación de una sola página para que esto funcione.
Añada un parámetro con una marca de tiempo completo o una identificación única a cada llamada http que no desee almacenar en caché. Funciona como un campeón. Solía tener el mismo problema al usar plantillas en Angular. Acabo de agregar un interceptor http y agregué una marca de tiempo a cada llamada y el problema desapareció.
Hay razones específicas por las que ninguna de las cosas que ha intentado ha arreglado las cosas.
En primer lugar, el uso del elemento <caching>
en web.config no instruye al navegador sobre cómo almacenar en caché la respuesta. Se usa para configurar cómo el servidor IIS guarda en caché la respuesta para que pueda ser reutilizada en futuras solicitudes. Here está la documentación que explica eso.
Luego, tus etiquetas <meta>
. Normalmente, el control de caché se realiza mediante encabezados http reales. Si bien puede usar etiquetas <meta>
para establecer encabezados que no están especificados en absoluto en su encabezado de respuesta HTTP, NO anularán los encabezados http que ya se están configurando. IIS tiene valores predeterminados para el almacenamiento en caché en los encabezados de respuesta, sus etiquetas <meta>
realidad no harán nada. <meta>
etiquetas <meta>
solo son realmente útiles cuando carga un file:///
url.
Para lograr de manera confiable lo que está tratando de hacer, realmente necesita que el servidor envíe los encabezados de control de caché que desea usar. Esto puede variar dependiendo de qué navegadores intente admitir, pero dado que está usando angular, podría asumir que está soportando navegadores modernos, lo cual es simple. A continuación, se inhabilitará el almacenamiento en caché de TODOS los archivos estáticos en su sitio web, que probablemente no sea exactamente lo que usted desea, pero podría servir como una guía.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<location path=".">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
</system.webServer>
</location>
</configuration>
Sin embargo, lo primero que debe hacer es examinar los encabezados de respuesta actuales que IIS le está enviando. Esto se puede hacer fácilmente usando las herramientas de desarrollo de Chrome. Si ve un encabezado Cache-Control:
en la respuesta, esto confirmará mi razonamiento sobre por qué sus etiquetas <meta>
no funcionan.
Si está generando el HTML para su aplicación angular no con un archivo .html estático sino que lo está generando mediante ASP.NET, su mejor opción es agregar código en su controlador que establece el encabezado del caché.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Si desea admitir navegadores mucho más antiguos o rotos, existen otros recursos que describen qué encabezados adicionales necesitará agregar, lo que nuevamente se puede hacer usando el código web.config o ASP.NET. Solo quiero volver a iterar: si todavía tiene problemas, asegúrese de que está viendo los encabezados de respuesta enviados por el servidor.
Para las páginas ASP.NET no desea almacenar en caché en ningún lugar,
HttpContext.Current.Response.Cache.SetCacheability
(HttpCacheability.Server);
HttpContext.Current.Response.Cache.SetNoStore();
Response.Cache.SetExpires(DateTime.Now);
Response.Cache.SetValidUntilExpires(true);
Esto le indica a los servidores proxy de almacenamiento en caché que solo el servidor tiene permitido almacenar en caché la página y le dice al servidor que no la guarde en caché. Las últimas dos líneas de código le piden al navegador que no lo guarde en caché. El código anterior lleva a estos tres encabezados:
Cache-Control:no-cache, no-store
Pragma:no-cache
Expires:-1
También puede agregar algo exclusivo a la cadena de consulta para evitar el almacenamiento en caché del navegador.
.post(this.API + "/products/store?unique=milliseconds", body, {headers: headers} )