【问题标题】:Google App Engine, index.html cached after deploy in express/react appGoogle App Engine,在 express/react 应用中部署后缓存的 index.html
【发布时间】:2020-12-23 04:37:05
【问题描述】:

我有一个部署到 Google App Engine 的 nodejs10 应用程序。如果用户之前在 Chrome 中使用过该应用程序,则重新部署该应用程序时该应用程序将无法运行。该应用程序是使用 create-react-app 创建并使用 webpack 构建的,因此 css 和 js 在构建时被重命名,但引用这些文件的 index.html 不是。因此,当用户在部署后访问该站点时,它将获得引用不再存在的 js/css-files 的缓存 index.html。这反过来又导致Uncaught syntax error: unexpected token '<'

我发现让应用程序再次运行的唯一方法是打开检查器,禁用缓存并重新加载页面。不用说,这不是您可以要求最终用户做的事情。

我已经为此搜索了解决方案,并发现了类似的问题但不完全相同,或者如果它们相同,则没有可用的解决方案。

当没有对现有静态文件发出请求以使 React 路由器正常工作时,express 代码为 index.html 提供 res.sendFile

app.get('*', (req,res) =>{
    try {
        res.sendFile(path.join(public+'/index.html'))
    } catch(e) {
        res.status(404).send()
    }
});

问题是我最近将应用程序从个人谷歌云帐户转移到了我的企业帐户,我以前从未遇到过这个问题。所以要么我改变了一些东西来导致这个,要么App Engine已经改变了。

响应标头(响应代码 304)如下所示:

Accept-Ranges: bytes
Cache-Control: public, max-age=0
Content-Encoding: gzip
Content-Length: 1200
Content-Type: text/html; charset=UTF-8
Date: Thu, 03 Sep 2020 20:43:51 GMT
ETag: W/"967-49773873e8"
Last-Modified: Tue, 01 Jan 1980 00:00:01 GMT
Server: Google Frontend
Vary: Accept-Encoding
X-Cloud-Trace-Context: 7f98678c2ba7dc90ad204b67bec766df;o=1
X-Powered-By: Express

因此,您可以看到文件上的“最后修改”日期是 1980 年 1 月 1 日。我已经验证该文件实际上在应用引擎上具有最后修改日期。但是在部署的本地构建文件夹中,该文件具有当前日期。不知道这是否是导致问题的原因。

所以我有点迷路了。我想我可以破解“最后修改”的标题,但这并不像是一个好的解决方案。而且我也担心同样的行为可能会发生在其他文件上,这会导致类似的问题。还有其他人遇到这个并提出了解决方案吗?

【问题讨论】:

  • 确实,如果这是缓存引起的问题,您将无法解决它,因为无法清除客户端浏览器缓存。搜索此类错误,我发现它可能与您的应用程序的路由系统和app.yaml 配置有关。考虑到这一点,您能否看看这个类似的案例here 并检查这两个配置中的更改是否有助于您解决您的案例?
  • @gso_gabriel 虽然链接的问题给出了相同的错误消息,但它不是同一个问题。就我而言,如果我清除浏览器缓存,一切正常。我知道可能无法清除客户端缓存,但至少我可以阻止为将来的版本缓存文件。在我部署的代码中,提供 css/js 文件没有问题,只是缓存的 index.html 尝试访问错误的文件,因为它们在重建时更改了名称。
  • 嗨@ChristofferHallqvist 我已经发布了一个答案,为删除缓存提供可能的解决方案,这可能会对您有所帮助。如果它对您有帮助,请考虑支持/接受它。 :)

标签: node.js reactjs express google-app-engine create-react-app


【解决方案1】:

如原问题所述,index.html 上的 etag 为: W/"967-49773873e8"

我认出了 etag,我的 appengine + express 网站上的一个 etag 示例是 W/"bd1-49773873e8"

之后我注意到我所有的 etag 都以相同的哈希结尾:49773873e8 这应该是正在发送的文件正文的哈希值。

似乎 express 或应用引擎出现问题,导致哈希始终以 49773873e8 结尾

第一部分来自文件的长度,因此如果两个文件(或旧的 index.html)长度相等,则存在哈希冲突。

【讨论】:

    【解决方案2】:

    人。

    经过努力,我找到了正确的解决方案。

    从 express 提供静态文件时,普通中间件不适用。您需要使用 express.static 中的自定义函数setHeaders

    • 一方面,我们在访问“/”路由时提供 index.htmnl。这使用普通的快递标头
    • 另一方面,正在通过静态服务请求 index.html。这不使用其他标题。

    所以我们需要涵盖这两种情况。

    代码如下:

    app.use(express.static('build', { etag: false, lastModified: false, setHeaders: (res, path) => {
      // No cache for index html otherwhise there's gonna be problems loading the scripts
      if (path.indexOf('index.html') !== -1) {
        res.set('Cache-Control', 'no-store')
      }
    } }));
    
    
    app.set('etag', false)
    
    app.disable('x-powered-by');
    
    app.use((req, res, next) => {
      // hide x-powered-by for security reasons
      res.set( 'X-Powered-By', 'some server' );
      // This should apply to other routes
      res.set('Cache-Control', 'no-store')
      next()
    })
    
    app.get('/', (req,res) =>{
      // I think this is redundant
      res.set('Cache-Control', 'no-store')
      res.sendFile(path.join(__dirname+'/build/index.html'), { etag: false, lastModified: false });
    });
    
    app.get('*', (req,res) =>{
      // I think this is redundant
      res.set('Cache-Control', 'no-store')
      res.sendFile(path.join(__dirname+'/build/index.html'), { etag: false, lastModified: false });
    });
    
    const port = process.env.PORT || 8080
    app.listen(port, () => console.log('App listening on ' + port));
    
    

    【讨论】:

      【解决方案3】:

      我在奇怪的时间戳上遇到了完全相同的问题。

      事实证明这是设计行为,因为所有时间戳在应用引擎部署时均为零。见:https://issuetracker.google.com/issues/168399701

      我是这样解决的:

      app.use("/", express.static(root, { etag: false, lastModified: false }));
      

      或者对于单个文件:

      app.get("/*", async (req, res) => {
        return res.sendFile("index.html", { root, lastModified: false, etag: false });
      });
      

      【讨论】:

        【解决方案4】:

        我怀疑您还使用包含index.html 的目录调用app.use(express.static())。将模板文件从静态内容移至单独的目录。

        【讨论】:

          【解决方案5】:

          如 cmets 中所述,您不会清除客户端浏览器缓存。所以,这对你来说不是一个可行的解决方案。但是,考虑到一切正常,但只有缓存问题,我已经搜索并找到了可能的替代方案。

          似乎这个存储库here,称为nocache,是一个关闭缓存的中间件,可以在Javascript中使用。您只需要通过运行npm install --save nocache 来安装它,然后将以下行添加到您的代码中。

          const nocache = require('nocache')
          app.use(nocache())
          

          这是我从这个案例here 中找到的解决方案,它是在客户端停止缓存的解决方案。

          【讨论】:

          • 嗯,当然这是“解决”它的一种方法,但这是一种相当蛮力的方法,而且一开始就不需要这种方法。如果缓存一开始就可以正常工作,那么就不需要像这样的破解了。我正在寻找解释为什么首先会出现这个问题,为什么最后修改日期是 1980 年,以及是否有意这样做。
          • 嗨@ChristofferHallqvist 似乎你不是唯一一个,因为另一种情况here 和你有同样的情况,正如另一个人提到的那样,这确实是一个缓存问题。它还包括不同的可能解决方案。如果您认为此案例是 App Engine 造成的问题,您可以报告它here
          • 谢谢,看来问题确实是由 App Engine 引起的,所以我正在关注该案例的报告问题,并希望它会导致正确的解决方案,而不是在你不应该这样做。
          • 我也遇到了同样的问题,没有找到解决办法。我正在尝试这里描述的东西。 @ChristofferHallqvist,你解决了吗?
          猜你喜欢
          • 2019-08-21
          • 2023-03-02
          • 2015-11-13
          • 2020-08-18
          • 1970-01-01
          • 2013-02-05
          • 2019-02-02
          • 2019-10-10
          • 2018-05-19
          相关资源
          最近更新 更多