简体   繁体   English

使用单页应用程序(SPA)时如何在不刷新浏览器的情况下处理过期文件?

[英]How to handle expired files without refreshing the browser when using Single Page Application (SPA)?

I have done a full Single Page Application (SPA) application using Angularjs. 我使用Angularjs完成了一个完整的单页面应用程序(SPA)应用程序。

So far so good. 到现在为止还挺好。

As anyone knows, all javascript files are loaded in the first time access. 众所周知,所有javascript文件都是在第一次访问时加载的。 Or, some file are loaded in lazy mode style when needed. 或者,某些文件在需要时以惰性模式加载。

So far so good... 到现在为止还挺好...

The situation is: the server updates all files (html partials, javascripts, css's) and the client remain with a lot of files out-dated. 情况是:服务器更新所有文件(html partials,javascripts,css),客户端仍然有很多文件过时。

This would be simply solved refreshing the browser, hit F5 key, control+f5, or refresh button in the browser. 这将简单地解决刷新浏览器,点击F5键,控制+ f5或浏览器中的刷新按钮。 But this concept does not exists when working with SPA. 但是在使用SPA时这个概念并不存在。

I'm not sure how to solve this problem. 我不知道如何解决这个问题。

I could detect somehow (doing a ping maybe) and just to re-load that specific file. 我可以以某种方式检测(可能执行ping操作)并只是重新加载该特定文件。 With document.write strategy. 使用document.write策略。 But now rises another problem, I have a single javascript file with all javascript minified. 但现在又出现了另一个问题,我有一个javascript文件,所有javascript都缩小了。

I could try to force a full reload in the browser or force to re-login (and reload because login are SPA part). 我可以尝试在浏览器中强制完全重新加载或强制重新登录(并重新加载,因为登录是SPA部分)。

But reloading is an ugly solution, imagine the client lose all data in the form because he was unlucky the server have just updated. 但重新加载是一个丑陋的解决方案,想象客户端丢失表单中的所有数据,因为他不幸的是服务器刚刚更新。 And worse, I must now create some "auto-save" feature just because of this. 更糟糕的是,我现在必须创建一些“自动保存”功能正因为如此。

I'm not sure how to handle this, if possible, doing in "angular way". 如果可能的话,我不知道如何处理这个问题,以“角度方式”进行。

I wonder how google gmail handles this because I stay logged for many many hours without logging of. 我想知道google gmail是如何处理这个的,因为我在没有记录的情况下保持记录很多个小时。

As others have already suggested, keep the logged user on the old version of your webapp. 正如其他人已经建议的那样,将记录的用户保留在旧版本的webapp上。

Not only what you ask is difficult to do in Angular, but it can also lead to a bad user experience and surprising behaviour, since there may not be a mapping between what the user is doing with the old version and what the new version provides. 不仅在Angular中你很难做到这一点,而且它还会导致糟糕的用户体验和令人惊讶的行为,因为用户使用旧版本和新版本提供的内容之间可能没有映射。 Views may be removed, renamed, split or merged. 可以删除,重命名,拆分或合并视图。 The behaviour of the same view may have changed, and doing so without notice for the user may cause mistakes. 相同视图的行为可能已更改,并且在没有用户通知的情况下这样做可能会导致错误。

You made an example with Gmail, but may have noticed that changes to the UI always happen after you logout, never while you're using it. 您使用Gmail做了一个示例,但可能已经注意到在您注销后总是会发生对UI的更改,而不是在您使用它时。

First of all, if your app is an intranet website used during office time, just update it while nobody is using it. 首先,如果您的应用程序是在办公时间内使用的Intranet网站,只需在没有人使用它时更新它。 This is a much simpler solution. 这是一个更简单的解决方案。

Otherwise, if you need to provide 24/24 availability, my suggestion is: 否则,如果您需要提供24/24的可用性,我的建议是:

  • When you deploy the new version of your SPA, keep the old version in parallel with the new version, keep the current users on the old version, and log new users to the new version. 部署新版本的SPA时,请将旧版本与新版本并行保留,将当前用户保留在旧版本上,并将新用户记录到新版本。 This can be made in a number of ways depending on your setup, but it's not difficult to do. 这可以通过多种方式进行,具体取决于您的设置,但这并不难。

  • Keep the old version around until you're confident that nobody is still using it or you're pretty sure that the new version is ok and you don't need to rollback to the old version. 保留旧版本,直到您确信没有人仍在使用它,或者您确信新版本正常并且您不需要回滚到旧版本。

  • The backend services should be backward-compatible with the old version of the frontend. 后端服务应该与旧版本的前端向后兼容。 If that's not possible you should keep multiple version of the backend services too. 如果这不可能,您也应该保留多个版本的后端服务。

As the rest of the guys said a solution can be to versioning your files. 正如其他人所说,解决方案可以是对文件进行版本控制。 So every time that your browser check those files out the browser notice that the files are different to the ones that are in the server so the browser cache the new files. 因此,每次浏览器检查这些文件时,浏览器都会注意到文件与服务器中的文件不同,因此浏览器会缓存新文件。

I suggest to use some build tool like gulp, grunt or webpack, the last one is becoming more popular. 我建议使用一些构建工具,如gulp,grunt或webpack,最后一个变得越来越流行。

By the moment I use gulp for my projects. 到目前为止,我使用gulp进行项目。 I´m moving to webpack though. 我正在转向webpack。

if you are interested in gulp you can have a look to gulp-rev and gulp-rev-replace plugins. 如果您对gulp感兴趣,可以查看gulp-rev和gulp-rev-replace插件。

What do they do? 他们在做什么?

let´s say that we have the next file in your project app.js what you get after apply gulp-rev to your project is something like app-4j8888dp.js then your html file where the app.js is injected is still pointing to app.js so you need to replace it. 假设我们在您的项目app.js有下一个文件,将gulp-rev应用到您的项目之后得到的就是app-4j8888dp.js然后注入app.js的html文件仍然指向app.js所以你需要替换它。 To do that you can use gulp-rev-replace plugin. 为此,您可以使用gulp-rev-replace插件。

eg. 例如。 gulp task where gulp任务在哪里

var gulp = require('gulp');
var rev = require('gulp-rev');
var revReplace = require('gulp-rev-replace');
var useref = require('gulp-useref');
var filter = require('gulp-filter');
var uglify = require('gulp-uglify');
var csso = require('gulp-csso');

gulp.task("index", function() {
  var jsFilter = filter("**/*.js", { restore: true });
  var cssFilter = filter("**/*.css", { restore: true });
  var indexHtmlFilter = filter(['**/*', '!**/index.html'], { restore: true });

  return gulp.src("src/index.html")
    .pipe(useref())      // Concatenate with gulp-useref
    .pipe(jsFilter)
    .pipe(uglify())             // Minify any javascript sources
    .pipe(jsFilter.restore)
    .pipe(cssFilter)
    .pipe(csso())               // Minify any CSS sources
    .pipe(cssFilter.restore)
    .pipe(indexHtmlFilter)
    .pipe(rev())                // Rename the concatenated files (but not index.html)
    .pipe(indexHtmlFilter.restore)
    .pipe(revReplace())         // Substitute in new filenames
    .pipe(gulp.dest('public'));
});

if you want to know further details see the links bellow. 如果您想了解更多详细信息,请参阅下面的链接。

https://github.com/sindresorhus/gulp-rev https://github.com/jamesknelson/gulp-rev-replace https://github.com/sindresorhus/gulp-rev https://github.com/jamesknelson/gulp-rev-replace

A single page application is that, a single stack that controls the client logic of your application. 单页应用程序是控制应用程序客户端逻辑的单个堆栈。 Thus, any navigation done through the application should be handled by your client, and not by the server. 因此,通过应用程序完成的任何导航都应该由您的客户端处理,而不是由服务器处理。 The goal is to have a one single "fat" HTTP request that loads everything you need, and then perform small HTTP requests. 目标是让一个“胖”HTTP请求加载您需要的所有内容,然后执行小的HTTP请求。

That's why you can only have one ng-app in your apps. 这就是为什么你ng-app中只能有一个ng-app You are not suppose to have multiple and just load the modules you need (although the AngularJS team wants to move that way). 您不应该拥有多个并且只需加载您需要的模块(尽管AngularJS团队希望以这种方式移动)。 In all cases, you should serve the same minified file and handle everything from your application. 在所有情况下,您应该提供相同的缩小文件并处理应用程序中的所有内容。

It seems to me that you are more worried about the state of your application. 在我看来,你更担心你的申请状态 As Tom Dale (EmberJS) described in the last Cage Match, we should aim to have applications that can reflect the same data between server and client at any point of time. 正如Tom Dale(EmberJS)在上一次Cage Match中所描述的那样,我们的目标应该是能够在任何时间点在服务器和客户端之间反映相同数据的应用程序。 You have many ways to do so, either by cookies, sessions or local storage. 您可以通过cookie,会话或本地存储来实现此目的。

Usually a SPA communicates with a REST based server, and hence perform idempotent operations to your data. 通常,SPA与基于REST的服务器通信,因此对数据执行幂等操作。

tl;dr You are not supposed to refresh anything from the server (styles or scripts, for instance), just the data that your application is handling. tl; dr您不应该从服务器(例如样式或脚本)刷新任何内容,只需刷新应用程序正在处理的数据。 An initial single load is what SPA is all about. 最初的单一负载就是SPA的全部内容。

separate your data and logic and reload the data using ajax whenever you want, for that i will suggest you use REST API to get the data from server. 分离你的数据和逻辑,并随时使用ajax重新加载数据,因为我建议你使用REST API从服务器获取数据。

SPA helps you to reduce the HTTP request again and again but its also require some http request to update a new data to view. SPA可帮助您一次又一次地减少HTTP请求,但它还需要一些http请求来更新要查看的新数据。

Well, you would have to unload the old existing code (ie the old AngularJS app, modules, controllers, services and so on). 好吧,你必须卸载旧的现有代码(即旧的AngularJS应用程序,模块,控制器,服务等)。 Theoretically, you could create a custom (randomized) app name (with all modules have this prefix for each unique build!) and then rebuild your app in the browser. 从理论上讲,您可以创建一个自定义(随机)应用程序名称(所有模块都为每个唯一版本都有此前缀!),然后在浏览器中重建您的应用程序。 But seriously.. that's a) very complex and b) will probably fail due memory leaks. 但严重的是......这是a)非常复杂,b)可能因内存泄漏而失败。

So, my answer is: Don't. 所以, 我的回答是:不要。

Caching issues 缓存问题

I would personally recommend to name/prefix all resources depended by a build with a unique id; 我个人建议命名/前缀具有唯一ID的构建所依赖的所有资源; either the build id, a scm hash, the timestamp or whatever like that. 构建id,scm哈希,时间戳或类似的东西。 So, the url to the javascript is not domain.tld/resources/scripts.js but domain.tld/resources-1234567890/scripts.js which ensures that this path's content will never conflict with a (newer) version. 因此,javascript的url不是domain.tld/resources/scripts.js而是domain.tld/resources-1234567890/scripts.js ,它确保此路径的内容永远不会与(较新的)版本冲突。 You can choose your path/url like you want (depending on the underlaying structure: it is all virtually, can you remap urls, etcpp). 您可以根据需要选择路径/网址(取决于底层结构:它实际上是全部,您可以重新映射网址,等等)。 It would be even not required that each version will exist forever (ie map all resources-(\\d+)/ to resources/ ; however, this would be not nice for the concept of URLs. 甚至不要求每个版本将永远存在(即将所有resources-(\\d+)/映射到resources/ ;但是,这对于URL的概念来说并不好。

Application state 申请状态

Well, the question is how often will the application change that it would be important that such reloads are required. 那么,问题是应用程序多久会改变一次,重要的是需要重新加载。 How long is the SPA open in a browser? SPA在浏览器中打开多长时间? Is it really impossible to support two versions at the same time? 是否真的不能同时支持两个版本? The client (the app in the browser) could even send its own version within the HTTP requests. 客户端(浏览器中的应用程序)甚至可以在HTTP请求中发送自己的版本。

In the beginning of a new application, there are a lot of changes that would require a reload. 在新应用程序的开头,有很多需要重新加载的更改。 But soon after your application has a solid state, the changes will be smaller and would not require a reload. 但是,在您的应用程序处于固定状态后不久,更改将会更小,并且不需要重新加载。 The user itself will make more refreshs.. more than we ever expected :/ 用户本身将进行更多更新...比我们预期的更多:/

As with what everyone else is saying... 正如其他人所说的那样......

Don't, and while socket.io could work it's asking for trouble if you are VERY careful. 不要,而socket.io可以工作,如果你非常小心,它会要求麻烦。

You have two options, upon server update invalidate any previous session (I would also give users a half hours notice or 5 minutes depending on application before maintenance would be done. 您有两个选项,在服务器更新时使任何先前的会话无效(我还会在维护完成之前向用户提供半小时通知或5分钟,具体取决于应用程序。

The second option is versioning. 第二个选项是版本控制。 If they are on version 10, then they communicate with backend 10. If you release version 11 and they are still on 10 then they can still communicate with backend 10. 如果它们在版本10上,那么它们与后端10进行通信。如果您发布版本11并且它们仍然在10上,那么它们仍然可以与后端10通信。

Remember Google wave? 还记得谷歌吗? It failed for a reason. 它失败的原因。 Too many people writing one source as the same time causes more problems then it solves. 太多人同时写一个来源会导致更多的问题然后解决。

use $state service. 使用$ state服务。 create state during loading page using ctor. 使用ctor在加载页面期间创建状态。 after specified time re create state and load page. 在指定的时间后重新创建状态和加载页面。

 function(state) { state.stateCtor(action); $state.transitionTo(action + '.detail', {}, { notify: true }); } 

对文件进行版本控制,以及每个更新增量版本号,浏览器将自动更新它。

My solution consists of several points. 我的解决方案包括几点。

  1. While this is not important, but I send one JavaScript file to the client side, I use grunt to prepare my release. 虽然这并不重要,但我将一个JavaScript文件发送到客户端,我使用grunt来准备我的版本。 The same grunt file adds to the JavaScript tag a query with version number. 相同的grunt文件将带有版本号的查询添加到JavaScript标记中。 Regardless of whether you have one file or lots of files, you need to add a version number to them. 无论您有一个文件还是大量文件,都需要为它们添加版本号。 You may need to do this for resources as well. 您可能还需要为资源执行此操作。 (check at the end for an example) (最后查看一个例子)

  2. I send back in all my responses from the server (I use node) the version number of the app. 我从服务器(我使用节点)发回我的所有响应中的应用程序的版本号。

  3. In Angular, when I receive any response, I check the version number against the version number loaded, if it has changed (this means the server code has been updated) then I alert the user that the app is going to reload. 在Angular中,当我收到任何响应时,我会根据加载的版本号检查版本号,如果它已更改(这意味着服务器代码已更新),那么我会提醒用户应用程序将重新加载。 I use location.reload(true) ; 我使用location.reload(true) ;

  4. Once reloaded the browser will fetch all new files again because the version number in the script tag is different now, and so it will not get it from cache. 重新加载后,浏览器将再次获取所有新文件,因为脚本标记中的版本号现在不同,因此它不会从缓存中获取。

Hope this helps. 希望这可以帮助。

<script src="/scripts/spa.min.js?v=0.1.1-1011"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在不使用“路由”的情况下使用AngularJS刷新单页应用程序时如何验证登录用户? - How to authenticate logged in user when refreshing single page application using AngularJS without “Routing”? 如何使用AngularJS单页应用程序处理页面刷新 - How do I handle page refreshing with an AngularJS Single Page Application 如何在AngularJS SPA应用程序中处理浏览器刷新? - How can I handle a browser refresh in an AngularJS SPA application? 如何处理页面刷新 - How to handle page refreshing PageSpeed服务/库如何帮助单页应用程序(SPA)? - How does PageSpeed Service/Library helps a Single Page Application (SPA)? 使用AngularJS和Sitecore(SPA)构建单页应用程序 - Building a Single Page Application with AngularJS and Sitecore (SPA) 概念说明SPA(单页应用程序) - Concept explanation SPA (Single Page Application) single-spa - 如何在不使用 SystemJS 的情况下加载 Angular 应用程序 - single-spa - how to load an Angular app without using SystemJS 如何在单页应用程序中处理分页? - How to handle pagination in Single Page Application? 如何使用Angularjs在URL内部没有#的单页应用程序? - How to have single page application without # inside the URL using Angularjs?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM