I have a web service where any user can start a process that takes somewhere between 15 seconds and 10 minutes to complete. The process is started with a POST request and the user is redirected to page that shows current progress of the process (e.g. https://example.com/progress-status/123).
My current implementation is to send HTTP header Refresh with value n;url=https://example.com/progress-status/123 where n is automatically changed between 5 and 120 according to expected time to completion and current server load. As a result, the progress status is automatically updated once every 5 seconds or more. After the progress has been completed, the status page will immediately redirect (HTTP 301 and Location header) to the completed job.
This works otherwise nicely but causes ugly flickering in Opera 42.0, which considers this to mean forced reload and skip all caches. I'm sending correct Cache-Control headers so using cached result for everything would be fine but Refresh header causes all caches to be ignored. (The status page contains some images and links to static CSS files so it does not make any sense to refresh those resources for every poll request.)
Is there any way to implement polling just the HTML page without JavaScript? I know that I could poll just the current status with Ajax query and then update the part of the currently visible page with the updated information. However, that will not work if user disables JavaScript. Rest of the service works without JavaScript so requiring JavaScript for something this simple seems bad. (I already have a GET submit button on the progress status page to force refresh manually.)
I know that HTTP Refresh header is not defined in HTTP 1.0 or HTTP 1.1 so this is a bit grey area. I'm looking for something that works in real world without JavaScript.
you can try the html meta refresh
<meta http-equiv="refresh" content="5"><!-- reloads the page after 5 seconds //-->
W3Schools doc on <meta>
Of course only put it if progress is < 100% :)
Not completely without, but you don't have to reload the whole page. Instead of that, you could just listen to SSE (server side events) and update the status value on the page (the element where it is contained).
I can't think of any way to do that. And much less one that entails good practices: use Javascript.
You can use a noscript tag to advise your users that JavaScript is necessary:
<noscript>
<h1>JavaScript is not enabled, please check your browser settings.</h1>
</noscript>
Realistically almost everyone has Javascript enabled nowdays.
Works Google Maps, FaceBook, etc, without JavaScript? No.
Why your web app will require that?
I complete agree with this phrase from #Matthew Trow answer:
I think sacrificing functionality for 99% of users to accommodate 1% is sheer bloody mindedness.
Related
I'm writing a sever application in go providing a Rest-API. If the server gets a GET without JSON-content-type header it serves an empty html-page having a javascript module in its head. This javascript code uses fetch to consume the Rest-API and populates then according the document.body with content fetched from the server. Each "link" in the content triggers further calls to the API and corresponding updates to the content.
So far so good. But I made two irritating observations.
(obviously) the "back" and "forward" buttons of the browser stay inactive. Which seems logical since there are no loaded URLs associated with the content changes.
If I come to my Rest-UI from an other page and hit the browser's back-button I get as expected the other page back but if I hit now the browser's forward-button I see the JSON-response from my initial fetch instead of my Rest-UI content. Reloading my page makes it all good again but I can't offer that behavior to any user :)
Are there common approaches to deal with this behavior? E.g. removing the browser controls completely, feeding the browser-history "by hand" with js-callbacks, caching directives, ... (I'm inexperienced with js)
The root of the problem is that I overloaded the response of a GET request on the server-side: if the GET-request accepts JSON the server returns JSON otherwise it returns a html-page with the javascript which consumes the JSON. I. e. the javascript fetch for the JSON is the last GET-response for a given URL and goes as such into the browser's cache associated with that URL. A solution to that problem which works for me is to send a header with the JSON response turning of caching and signalling the browser with the "Vary"-header that the response depends on the "Accept"-header. An other solution might be to add distinct endpoints to the server for the Rest-requests.
I currently have a PHP script running in the background executing a PHP script reading a big table. At the same time it is sending the results to an API. This is done with unbuffered query.
On the top of this script, I've put
ignore_user_abort(true);
set_time_limit(0);
To make sure the script runs in the background until it is done. I also have a Javascript that is getting progress report from this script. But, when the page is reloaded, the progress is started again and it will start sending the data again to the API duplicating data.
I was wondering if there is a way to let the user continue on the script. So the script is already running in the background, but is there a way to return the user to the script so it'll be like they never left?
EX:
User starts importing, import is at 200 rows out of 1 million. They refresh the page and the page says 202 rows out of 1 million. 202 mil cause time has past importing more rows while the user has left since script is executing in the background.
Thank you in advanced
You can use websocket to this case. When you will establish new connection to websocket you can store the connection in cookies. Then when you will reload the page you can restablish connection to websocket server. On top of that you need have a websocket server that can read from cookie variables.
Could this be done with using a cookie ?
Each time it runs, update said cookie then if the page is refreshed use the information in the cookie to start where it left off and update the page ?
We have a news website where we cache a complete article page.
There are 4 areas that need to continue to be dynamic on that page:
View Counter: We add +1 to view_counts of that article when page loads.
Header: On the header of the website we check if session->id exists or not if it does we display a Welcome [Name], My Profile / Logout and if not we show Register / Login.
Comments: We display the comments made for that article.
Track User Behavior: We track every single action made by users on the site
Now the only way we could think of doing this is through AJAX calls:
$('#usercheck').load(<?php echo "'" . base_url() . "ajax/check_header'"; ?>);
And so on.
This is creating a massive load on CPU, but what would be the right/alternative way of approaching this?
Please see attached:
First of all, you do not have to use AJAX for every possible dynamic content, especially in the case of comments, you may as well load them via an iframe.
That way, you are not relying on Javascript to make the request.
It may even work for the counter.
However, you problem is not Javascript, nor the database server, based on what I can see from your graph. It seems to me you have some heavy PHP controllers, maybe you are loading a heavy framework just to have $session->id checked.
Further, what do you mean by "we track every single action"? How do you track them? Are you sending an AJAX request from every little thing or are you debouncing them with JS and only sending them one every 30 seconds or so?
My advice is that you consider the size of the PHP code you are calling, and slim it down as much as you can, even to zero if it seems feasible (by leveraging localStorage to keep track of you user session after the first login), and maybe loading the counter and the comments in alternative ways.
For example, I infer you are only checking the counter once per page load, ignoring subsequent loads by other users while the current user is reading the article, so your counter may happen to be out-of-date once i a while, depending on your traffic.
I going to explain it better: your page has n views, so when I load it, you request for n and then display n+1 to me. While I'm reading, the same page gets requested and viewed x times by other users. Your counter on the server has been surely updated to n+x, but the counter on my page still says "n views".
So, what's the point in being picky and showing n+1 to me and the not updating it, thus being off by x?
So, first of all the counter controller should be as slim as possible, and what if you loaded it within an iframe, auto updating without AJAX?
How to refresh an iframe not using javascript?
That would keep the counter up-to-date, you may render it with PHP just once per page view, and then just statically serve the resulting HTML file.
I have an intranet application written in classic ASP.
Whenever a user has been inactive for longer than the session time, I want the page they're on to reload which will redirect them back to the login page because the session variables will be empty.
I've tried a bunch of solutions, none of which seem to work reliably across all browsers.
It should be no surprise that IE is giving me the most problems.
Anyway, in my login script, I set the session timeout as so:
Session.Timeout = 15
I tried using the meta refresh tag but in IE (all versions) sometimes it would work, sometimes it wouldn't and I can't figure out why. I would take the session timeout and add one second like so:
<meta http-equiv="refresh" content="<% = CInt(Session.Timeout + 1) * 60 %>;url=/?timeout=true" />
Sometimes IE would do the refresh and other times it would just sit there. I know the session is timing out because when the browser wouldn't execute the refresh, if I hit refresh, I get directed to the login page.
Is there something funky about meta refresh and IE I'm missing?
The second approach I tried was to use JavaScript. Since JavaScript is required to be enabled for the intranet application, this seems like a good option which I implemented as so:
<% iTimeout = CInt((Session.Timeout * 60) + 1) * 1000 %>
<script>window_refresh = window.setTimeout(function(){window.location.href=window.location.href+"?timeout=true"},<% = iTimeout %>);</script>
Now this reliably reloads the page but it seems as if the timer on the server and the timer JavaScript is using in the browser are off because when the page is reloaded sometimes, the session is still valid.
I've tried changing the + 1 to +60 and that works most of the time but even then sometimes the page will refresh while the session is still valid.
Am I approaching this issue correctly?
I would definitely also approach the issue through JavaScript.
However, instead of redirecting the user back to the login page I would create some kind of keepalive script that runs every few minutes to make sure the session never times out if the user still has the page open in the browser.
If this is not a usable solution for some reason in your case, I would as a minimum remember to alert the user that the redirect is about to happen to avoid sudden redirects that totally suprises the user.
Anyway.. To answer your problem:
Does your page also load other resources like images, stylesheets and other stuff?
Files like these are loaded after the HTML is processed and if the JavaScript timeout is started before the last of the files are loaded, you may end up in a situation where the JavaScript timeout is started before the session timeout is started.
In this case the JavaScript timeout will trigger before the session timeout and that makes the redirect occur before the session timeout.
You say that you have tried increasing the amount of extra seconds to 60 and that the problem still occurs sometimes. Are you sure that no files are loaded after the JavaScript timeout is started? I would investigate this a bit, because it sounds like something resets the session timeout in your system.
In the past, when I've covered events, I've used a meta-refresh with a 5 minute timer to refresh the page so people have the latest updates.
Realizing that this may not be the perfect way to do it (doesn't always work in IE, interrupts a person's flow, restarts things for people with screen readers, etc.) I'm wondering if there's any other way to do handle this situation.
Is it possible to have something like ajax check every few minutes if the html file on the server is newer and have it print a message saying "Update info available, click here to refresh"?
If that's crazy, how about a javascript that just counts down from 5 minutes and just suggests a refresh.
If anyone could point me to tutorials or code snippets I'd appreciate. I just play a programmer on TV. :-)
Actually, your thought on a timed Ajax test is an excellent idea. I'm not sure that is exactly what StackOverflow uses, but it checks periodically to see if other answers have been posted and shows the user, on an interval, if there are updates.
I think this is ideal for these reasons:
It's unobtrusive - the reader can easily ignore the update if they don't care
It won't waste bandwith - no reloading unless the user chooses to
It's informative - the user knows there's an update and can choose to act on it.
My take on how - have the ajax script send off the latest post id to a script that checks for new scripts. This script can query your database to see if there are any new posts, and how many there are. It can return this number. If there are new posts, show some (non modal) message including the number of updates, and let the user decide what to do about it.
setInterval(function() {
if (confirm("Its Been 5 Minutes. Would you like to refresh")) {
window.location.reload(true);
//Or instead of refreshing the page you could make an ajax call and determing if a newer page exists. IF one does then reload.
}
}, 300000);
You can use the setInterval function in javascript.
here's a sample
setInterval("refresh function", milliseconds, lang);
You will use it passing a name to a function that actually refresh the page for the first param and the number of milliseconds between refresh for the second param (300000 for 5 minutes). The third parameter lang is optional
If the user would be interacting with the scores and clicking on things it would be a little rude to just refresh the page on them. I think doing something like a notification that the page has been updated would be ideal.
I would use jQuery and do an ajax call to the file on the server or something that will return the updated data. If it's newer than throw up a Growl message
Gritter - jQuery Growl System
Demo of what a Growl is using Gritter
A Growl message would come up possibly with whatever was changed, new scores and then an option within that message to refresh and view the new results.
jQuery Ajax information