Detect application version change on a single page application - javascript

today a question was raised here and I don't have an evident answer.
Assume that we concatenate and minify all resource files (CSS and Javascript) and declare them in the "Master-Page".
On a multi-page app, if a CSS file changes it will be recharged on the next full page load.
On a single-page app, the user can keep working for days and never recharge the main page where the CSS files are declared. The user will never see the changes until a Ctrl-F5 is issued.
I'm sure someone already thought of this and have an experience to share :)
For me, using WebSockets is not an option. First because it's overkill and second because not all my clients support the technology. Same reason applies to all WebSockets fallbacks... I won't keep hitting my servers because of this.
So, any ideas anyone? :)
BTW, we're using AngularJS if that can help for a specific solution.
Thanks!

I've getting through this same problem. My solution which is opinionated and may not respond to your criterias:
When I package my front-app and my server-app, I share a configuration file containing the current version of the front-app.
Front side: 75% of my routes change implicitly call a Webservice (route change resolve). SO each time I call my server I include a custom HTTP header (or a GET/POST param) containing the client version of the front-app.
Server side : I compare the front-app version (the one in the browser of the user, loaded last time user refreshed/loaded the SPA) with the front-app version of the shared configuration file :
If version matches : I Do nothing.
If version don't match I send a custom HTTP status error code (418 for example)
Then front side: I added a response Interceptor that intercepts any 418 error code and do a force-refresh of the whole app
That's it. Basically the event that "check" if the front-app version is the latest is a route change (that calls a WS via ajax). But you could add some infinite $interval calling a dedicated WS each 5 minutes or so...
I can add some code if needed.
Hope this helps ;)

Assuming that you are using AngularJS' routing via $route service and provider, then you can use $routeChangeSuccess event to perform a server request if there are significant changes that needs to be changed; if there are any then you can do a window.location.reload() to refresh the page and get all the updated resources and htmls.
The following process can be changed depending on how you want to implement it:
1. Setup a config file in your server indicating the app's version. You may also choose to assign different versions for different files but since you have concatenated all your resource files then I guess you may limit your version options in your configuration.
2. Create a service that contains all the necessary information(versions of files from the server) and methods to perform a server request to your server to check against the current file versions stored in the service.
3. Use $routeChangeSuccess event to perform a server request using the service that you have created in step 2, if the request returned a valid confirmation that there were changes then do the force page reload via window.location.reload().

I decided to add my final thoughts as an answer here too:
We went for a reduced solution for now.
As we have a "proxy service" that is (again for now) the only one that interacts with this application, we added the application version on the http header of all responses. If we receive a newer version, a popup appears notifying the user and a full page refresh is issued...
This solution won't work for applications that don't have their own "private" service.

Related

How to refresh ASPX page and Javascript code that has been cached by proxy service

The Issue
Recently, I deployed a page to production containing javascript which used setInterval() to ping a webservice every few seconds. The behavior can be summed up as follows:
Every X seconds, Javascript on the upcomingEvents.aspx page calls the hitWebService() function, which sits in the hitWebService.js file.
The X interval value set proved to be too small, so, I removed all references to hitWebService(), the hitWebService.js file itself, and the web service it was trying to reach.
Attempts to hit the web service from normal IP addressess dropped off, but I am still getting attempted hits from a number of users who use a proxy service.
My theory is that my upcomingEvents.aspx and hitWebService.js have been cached by the proxy service. Indeed, when I log the referrer strings when a user hits the error page (every so often, one of these users will get redirected here), they are being referred from upcomingEvents.aspx.
The issue is that the attempts to hit this web service are filling up the IIS logs at an uncomfortable rate, and are causing unnecessary traffic on the server.
What I have attempted
Removed web service completely
Deleting the hitWebService.js file, also replaced it with dummy file
Changed content expiration on IIS so that content expires immediately
Added Response.Cache.SetCacheability(HttpCacheability.NoCache) to the .vb codebehind on page
Completely republished site with changes
Restarted IIS, stopped and started IIS.
Interesting bits
I can alter the vb codebehind on UpcomingEvents.apsx to log session details, etc, and it seems to update almost instantly for the proxy service users
The Question
If my theory is correct, and the proxy server is indeed caching these the files hitWebService.js and upcomingEvents.aspx, are there any other routes that I can go down to force a code refresh, considering the above strategies haven't worked?
Thanks a lot,
In my case, i had a ajax call begin cached by asp.net. I used a param with the javascript date number so each call have a different querystring.
like this:
function addQueryStringAntiCache(url)
{
var d = new Date();
var n = d.getTime();
return url + (url.indexOf("?") == -1 ? "?" : "&") + "nocache=" + n;
}
you can do the same thing for script:
<script src="myScript.js?v=8912398314812" />
In case you have access to the machine, use fiddle to check it the browser even call to get the files or if it use it's own cache. In that case you can try to include metaData or http Header to prevent it caching it. Check this response
Hope it help you.

Differences between MVC routing and SPA routing ?

I know how a MVC application handles routing,
(/foo/bar get) request hits the server
route /foo/bar with get method is found or not found, if found route handles the request by calling a method which serves a view page with corresponding data filled up.
client gets a html document with many links to other pages.
Another link is another procedure just like this one.
However, I have been learning react+meteor pack, which is a SPA (single page application) without ssr(server-side rendering). The most critical part that gets me confused is routing.Let's say I have 3 different routes for my SPA. (/), (/route2), (/route3)
(/route2) request hits the server. What does the server serve ? The whole application code with (/route2) active or what ?
Let s say we are on (/) route and clicked (/route2) route. So what s happening now ? Does react empty the #mainDıv and put related component instead, from where, the bundle.js which already contains all of the views' html as components ?
Is there a way to send only requested page's html and js, and after showing the content, getting other pages' html and js in the background, without client even feels. So that when another route is hit, only data will be on the wire.
Finally , only sending the related page's html - css - js when requested,I don t don't know if such a technique exists, seems to lack the SPA experience, but I am not sure If it would lack SPA expereince. It would be great to explain how to approach this issue.
With a SPA you typically (read: virtually always) configure your server to serve the same bootstrap HTML/Javascript regardless of which URL has been requested. A request for /route2 will get the same HTML response as a request for / or any other URL (unless you have specific exceptions for specific reasons). The SPA always starts with the same bootstrap code and examines the current browser's URL, then dynamically loads content as needed. How exactly that content is loaded and when it is loaded depends on the specific framework/code/circumstances/configuration, but yes, ultimately the contents of the DOM are dynamically being replaced by Javascript.

Do a 'soft-refresh' (only JS and CSS) of a WebSocket/AJAX application

I am developing an application using websockets, with a fallback on ajax.
Most of the logic resides on the client side of the application, models, views, etc.
While developing I often need to make minor changes, and do a refresh. The way I do this is by a hard browser refresh, which basically restarts the whole application.
This can take some time, these are the steps:
get the index.html from the server
index.html loads all the javascript files
javascript creates the app and starts the websocket
on succesfull websocket connection the server will send the init data
the init data from the server is recieved by the client and the page is generated
In a normal situation this will be ok, because as soon as the app is loaded, there is no more refresh.
But this get's painfull while developing, so I thought of the following solution:
After I made my CSS changes, I run the following script:
softreset: function(){
var queryString = '?reload=' + new Date().getTime();
$('link[rel="stylesheet"]').each(function () {
this.href = this.href.replace(/\?.*|$/, queryString);
});
}
This resets all the CSS instantly, so I do not need to do a complete refresh. One step out the way.
Often times this is not enough, I also need new content, so I want to do the following:
question
I need to unload all the JS files on the page, except for the one that holds the websocket connection.
All the DOM elements, Objects, Events that are associated with these files need to be removed to.
I need to get the new JS files from the server.
Load them into the page, and fire the onload action
I tried working with the snippet I use for CSS, but it does not do the same trick. Anyone have an idea?
i think live.js may match your require partly

How to make auto-updating (ajax) counter correctly? Or how to disable network log?

I'm trying to make auto-reload counter (for ex.: Messages [num]).
So, I just in setTimeout(); getting JSON code from test_ajax.php. I think it's not correctly..
Can I send info by server (I think not, but suddenly I something don't know..)?
Why I think that's not correctly: because when I'm looking in my chrome network log (F12 -> network tab), I see a lot of requests (to test_ajax.php), but when, I'm visiting vk.com (great example for ajax) or facebook.com, I don't see any requests while something will not change.
So, what's incorrectly in my solution (or what's bad..)?
UPD: Sorry, vk.com sending requests to q%NUM%.queue.vk.com every 25s, but until 25s last request's status is "Pending". When someone, for example, sending me a message it immediately display it. And request has parameter "wait" which equals 25. This delay in requests doing on server side.. But how?
Ajax counter can be done in easy just include below files
index.html
counter.php (ajax file)
necessary images
JS file (for jquery paging call)
download link: https://docs.google.com/open?id=0B5dn0M5-kgfDcE0tOVBPMkg2bHc
What you are looking for is called COMET (also sometimes called Reverse AJAX) techniques.
Doing what you want to do, e.g. regular polls, is one way of doing it.
A lot is actually happening on the server side; to avoid recreating new connections on every poll, some servlet containers like Jetty started to implement techniques like Continuation which basically maintain a two-way connection open.
In the Java world, with Servlet 3, you have asynchronous calls as part of the specs.

IIS express 405 error - method not allowed

I am working on a component which uses xmlHttpRequest to get DOM element positions from a xml on the server. Than after drag and drop I update the xml with the new positions and I want to post it back via XMLHttpRequest to the server to update the same file.
The responseText message states that HTTP Error 405.0 - Method Not Allowed. The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used.
I checked the applicationhost.config file and looks like every handler is configured with POST method. Also turned on all the features of IIS on Win 7 components.
My pc: Win7 home basic, visual studio professional, iis 7.5 express.
p.e.: I don't use webrequest method since mainly using javascript for the update process, because of the drag and drop functionality of the mootools library.
Thank you in advance!
The configuration you mention in your comment, sets the default IIS modules for handling "static files", that is responding to GET requests by returning a file based on mapping the URI path to the file system.
These are set up to handle all verbs but to 405 to everything except GET and HEAD because that is the default IIS behaviour for "static files" is to refuse to allow them to be POSTed to (or PUT to, or DELETEd).
The bug therefore is that the URI you are POSTing to isn't mapping to your handler for dealing with the data the javascript is POSTing. If that handler is an ASPX page, then check that other ASPX pages are working and that the correct URI is used. Then try debugging it with a simple HTML form that POSTs appropriate data (or even inappropriate data so you can at least get an error message about the data being wrong rather than it ending up somewhere that refuses to handle POST at all).
If the code to handle the POST is in an IHttpModule or IHttpHandler, then you need to add something to the web.config to override the default for the URI(s) in question.
Is your component and the server handling the XMLHttpRequests served from the same origin? Ie. is it served from the same, protocol://host:port combination. If not, the browser will issue a HTTP OPTIONS instead of the POST you are expecting it to. To handle this situation either do:
JSONP
Cross-origin resource sharing
I am closing this conversation since the issue was resolved with JSON request and object mapping via WebService. I assume the problem was a security one regarding to local permission configuration on the directory.
Thank you for your help!
Kornél

Categories