📜 ⬆️ ⬇️

How to make the site work in the form of a Web App (an uninteresting example of a private solution, which is also poorly described)

Probably, this is a kind of continuation of the theme “ Differences in the adaptation of the site and AJAX web applications for iOS ” and the development of the idea from my comment there.

The topic is old, but for many people it is still relevant. In general, there will be many particulars inside, since the goal is not to come up with a universal solution, but just need to make one specific site work as a Web App, without resorting to large modifications. In general, as usual, who cares - under the cat, the rest pass by, probably.

So, we denote introductory, tasks and problems: it is necessary to make the website (regular, nothing special) work as a Web App, without jumping out to Safari and remember what page the client was on and what he did there. I think that those who read up to this point know perfectly well what problems do not allow doing all of the above without doing anything: any normal link opens in Safari, if you switch to another application from the Web App, or minimize it, it will be opened That page is shown, which, in fact, saved as a Web App - the main one most often.

In general, dry tasks: 1) to make sure that links are not thrown out in Safari; 2) to make the session remembered; 3) to make, that the open page was remembered. Unlike the original topic, I set the tasks in exactly this order; it will be clear below why.
')
They drove to decide!

Links should not spit out in Safari


This issue has long been beaten and resolved. You just need to catch all the clicks on the links in JS and redo them to location.assign () . (For some reason, since ancient times, instead of location.assign (), window.location assignment is used everywhere - I don’t know what this is connected with, probably, it was considered more correct when the trees were large.)

In general, here I did not invent anything new, I just had to slightly expand: 1) this applies only in standalone mode; 2) if the link is “external” (with a different host), then it does not apply (Safari opens); 3) if the link is an anchor (# some-shit), then only location.hash is replaced.

That is, turn on this handler for standalone, require the presence of a href link, and then debug it for a specific case. There will be no code here, because there is one line and a lot of particulars that are not interesting to anyone, because this is not their particular.

Session must be memorized


It's harder here. The problem is that when the Web App is restarted, no cookies are sent, no cookies — the session is new. The basket was lost. In general, bad. In the original topic there was a solution with reading and writing cookies directly from JS, but as I wrote in the comments, it doesn’t work very well in modern realities - the session cookie is now httpOnly, that is, JS is not visible at all.

We will decide a little bit differently: we will store the identifier in localStorage as well, but we will compare and manage the session from the server side, and pull at all this via ajax. In JS, we make about such a sausage (also for standalone mode only):

$.post('/super-puper-server-script.json', {'sid': localStorage.getItem('sid')}, function(data) { localStorage.setItem('sid', data.sid); if (data.loc) window.location = data.loc; }); 


We send the current sid value from localStorage and save what is returned, and if the location is still returned, go through it. Therefore, all the logic is put to the server, there we can get the current value of the session identifier, and, more importantly, we can understand which identifier is correct.

(Remark: in Yii, which I use, during authorization the session identifier changes, while the session data is saved. That is, to allow the user to save the basket (and other session data) during authorization, and at the same time to maintain authorization in general, such moments are necessary consider and not substitute the session identifier from localStorage into the session, in fact.)

And inside, from the server side, everything is also quite simple. I do not cite my code directly, not because I am a miser, but because it seems to me that if I describe the algorithm itself, you can easily code it yourself in any language, instead of shouting: “Ugh! PHP - unsubscribe! ”

The algorithm is something like this: get an identifier from JS, get an identifier from a cookie, compare, check exceptions (authorization, for example, or another legitimate identifier change), if different - apply from JS. Answer send the identifier that is in the current session. If something has changed, add the current location to the answer - in order for the page to reload, and the session data has already been applied.

The page should be remembered.


And here is the reason why I didn’t begin to solve this (more important in general) problem before the sessions. Well, for starters, I absolutely do not like the approach to the original theme - save all the clicks in localStorage and restore them from there. This is bad, because there are redirects, jumps and forms that change location, but will not be saved in localStorage. This is also bad, because, as elsewhere, there may be exceptions that you have to make in JS.

And then it dawned on me - we just learned with difficulty how to restore the session, why not keep the location there as well ?! And everything turned out to be so beautiful and correct: first, it makes sense to restore the location only when we restore the session (restart the web app), and in other cases it will be just extra gestures. Secondly, there are more opportunities to control what exactly to save (and what not to save) as the current page. And finally, this approach allows you to reload the page only once, in order to apply the correct session data and show the user what he saw.

Here is a sample code of what is from the server side, and yes, in PHP:

 $sid = $_POST['sid']; $loc = abs2rel($_SERVER['HTTP_REFERER']); $resid = false; if (!empty($sid) && !empty($_COOKIE['PHPSESSID']) && $sid != $_COOKIE['PHPSESSID']) { session_id($sid); $resid = true; } session_start(); $reloc = ($resid && isset($_SESSION['loc'])) ? $_SESSION['loc'] : false; $_SESSION['loc'] = $loc; return ['sid' => session_id(), 'loc' => $reloc]; 


A couple of comments to the code: naturally, this all starts only at POST via ajax; in checking the differences of identifiers, you can add more conditions when the identifier should change (validly); before saving the session to the session, you can also exclude any checks; The returned hash is automatically converted into JSON.

Perhaps I missed something, but in general it works very, very well in this way. Well, and, apparently, writing intelligible articles is not mine. Confusing and incomprehensible, but as it is ...

Source: https://habr.com/ru/post/271783/


All Articles