Angular不会在启用缓存的情况下更新页面

时间:2017-09-05 12:25:42

标签: angular caching iis webpack

我创建了一个有角度的网站,其中包含一个“添加”和一个“删除”表单来操作同一页面上的表格上的数据。

当我在本地或使用Chrome Dev Console(禁用缓存)进行测试时,当我添加新项目或删除新项目时,该表格会自动刷新。当我在客户端的生产服务器(IIS服务器)上测试它时,它仅适用于打开的Chrome开发者控制台。否则,他们必须使用CTRL + F5刷新缓存并在页面上显示更改。

这是组件上的代码:

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

我的猜测是,它与某些服务器配置或webpack代码有关。但是,我对后者并不熟悉,我只是把它留在了我使用的起始包装上。

我创建了a gist with the webpack,因为它是一个长文件

编辑1:经过一些额外的研究,我尝试在应用的根文件夹上的web.config文件中添加以下内容。

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

但是,我仍然有相同的行为。在Dev Console关闭的情况下添加项目,它不会更新表格。但是如果我打开了开发控制台并禁用了缓存,那么它就会更新它而不需要刷新。

编辑2 :使用隐身窗口无法解决问题。

编辑3 :在index.html上添加元标记无法再次解决问题。

<meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">

编辑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!'));

    }  
  }

编辑5

我能找到的唯一解决方案是每次使用location.reload(true)对数据进行更新时重新加载窗口。但同样,这仅适用于Firefox,而不适用于Chrome。我不会接受你必须放弃使用单页应用程序来实现这一目的的唯一原因。

3 个答案:

答案 0 :(得分:6)

有一些具体的原因,你所尝试过的事情都没有解决问题。

首先,使用web.config中的<caching>元素不会指示浏览器如何缓存响应。它用于配置IIS 服务器如何缓存响应,以便在将来的请求中重用它。 Here是解释这一点的文档。

接下来,您的<meta>代码。通常,缓存控制由实际的http标头完成。虽然您可以使用<meta>标记来设置http响应标头中未指定的标头,但它们将 NOT 覆盖已设置的http标头。 IIS在响应标头中具有缓存的默认值,您的<meta>标记实际上不会执行任何操作。当您通过<meta>网址加载时,file:///代码确实非常有用。

为了可靠地实现您尝试执行的操作,您需要实际让服务器发送您要使用的缓存控制标头。这取决于您尝试支持哪些浏览器,但由于您使用的是角度,我可能会认为您支持现代浏览器,这很简单。以下内容将禁用您网站中所有静态文件的缓存,这可能不是您想要的,但可以作为指南。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <location path=".">
    <system.webServer>
      <staticContent>
        <clientCache cacheControlMode="DisableCache" />
      </staticContent>
    </system.webServer>
  </location>
</configuration>

但是,您应该做的第一件事是检查IIS发送给您的当前响应标头!使用Chrome开发人员工具可以轻松完成此操作。如果您在回复中看到Cache-Control:标题,则会确认我的<meta>代码无法正常工作的原因。

如果您为角度应用程序生成HTML而不使用静态.html文件,而是使用ASP.NET生成它,最好的办法是在控制器中添加设置缓存标头的代码。 / p>

Response.Cache.SetCacheability(HttpCacheability.NoCache);

如果您想支持更旧或更糟的浏览器,那么还有其他资源可以描述您需要添加的额外标头,这也可以使用web.config或ASP.NET代码完成。我只想重新迭代:如果您仍然遇到问题,确定您正在查看服务器发送的响应标头。

答案 1 :(得分:2)

对于ASP.NET页面,您不希望在任何地方缓存,

HttpContext.Current.Response.Cache.SetCacheability
                            (HttpCacheability.Server);
HttpContext.Current.Response.Cache.SetNoStore();
Response.Cache.SetExpires(DateTime.Now); 
Response.Cache.SetValidUntilExpires(true); 

这告诉任何缓存代理服务器只允许服务器缓存页面并告诉服务器不要缓存它。后两行代码要求浏览器不要缓存它。上面的代码导致了这三个标题:

 Cache-Control:no-cache, no-store
 Pragma:no-cache
 Expires:-1

您还可以添加查询字符串的唯一内容,以防止浏览器缓存。

.post(this.API + "/products/store?unique=milliseconds", body, {headers: headers} )

答案 2 :(得分:1)

将一个带有完整时间戳或唯一ID的参数附加到您不想缓存的每个http调用。像冠军一样工作。我曾经在Angular中使用模板遇到同样的问题。我刚刚添加了一个http拦截器并为每个调用添加了一个时间戳,问题就消失了。