Storing State in the URL
antonz.org
antonz.org
Having the state stored in speaking URLs in a transparent manner allows advanced users to easily strip information they don't want to share.
badly neglected but the more recommended read.
Plus even in those instances where links are manually copied and pasted, you're still overestimating the competency of the average user to identify the risk of state in URLs even when it seems bloody obvious to us technical folk.
* they are not sent to the server
* hence, the URL size limit is that of the browser, not that of the backend handling the request
* hence, they disclose less info to the middlemen
* they can be shared easily from person to person
One drawback is that they require more processing on the frontend side.
As always, trade offs.
This is, usually, a huge disadvantage. E.g. the filter parameters in the article.
And, yes, you can use those too, especially for SPAs!
The fact that the url hash-fragment isn't sent to the web server is a mere default. There's no controlling what plugins or scripts do.
> hence, they disclose less info to the middlemen
Care to elaborate? I don't see how a url (over tls) exposes more information unless tls is MiTM'd.
> they can be shared easily from person to person
That's a property of the url itself, and not unique to the hash-fragment, per se?
> I don't see how a url (over tls) exposes more information unless tls is MiTM'd.
What is not sent cannot be hacked. I was not suggesting an explicit security feature, rather a state of things.
> That's a property of the url itself, and not unique to the hash-fragment, per se?
Yes, but it makes for a nice combo with the previous point, as the URL now contains 2 things: the Locator itself that your peer and the server will access and (resp.) serve, plus the context that only your peer will have access to.
But, it's pretty humorous at times to see people put all this effort into replicating what was once the default behavior of the web.
HATEOAS is new again?
Learnt recently that Base64 encoding and decoding in JS doesn't quite handle Unicode strings. One solution[1] is to URI encode/decode the text (e.g. JSON):
base64 = btoa(encodeURIComponent( str ))
str = decodeURIComponent(atob( base64 ))
[1] https://developer.mozilla.org/en-US/docs/Glossary/Base64#the...So I rolled my own solution to parse JSON parameters and integrated it with the framework for validation and OpenAPI support.
https://abdus.dev/posts/aspnetcore-model-binding-json-query-...
https://wgx.github.io/anypage/?eyJoMSI6IiBTdG9yaW5nIHN0YXRlI...
It will show the same exact page because I think that PWAs are stupid and I don't build them.
Don’t store user state in the URL, that may bite them when it’s shared.
I say that navigation state should be in the URL.
Visit https://www.dpreview.com/
Next, we open this article: https://www.dpreview.com/samples/7583235225/nikon-z-50mm-f1-...
Within the article, we click the main photo, which opens another page with a slideshow: https://www.dpreview.com/sample-galleries/8661039925/nikon-z...
As we're keenly interested in the slideshow, we use the next arrow to cycle through all 47 photos.
Now that we're done with that, the slideshow has no further use, so let's hit BACK to return to the article we came from, and BACK again to return to the homepage.
Doesn't work, we have to hit BACK 47 times first. Because in this case slideshow manipulation is seen as navigation, and thus part of history.
Is navigating a slideshow state or navigation in itself? You tell me, it's not very obvious. Each slide is bookmarkable so it very much looks like a navigation action. And yet it does not lead to a great experience.
[1] https://developer.mozilla.org/en-US/docs/Web/API/History/rep...
[2] https://developer.mozilla.org/en-US/docs/Web/API/History/pus...
That's a truism. You still have to decide what navigation is.
- opening or closing a modal
- switching between representations (example: grid view vs list view)
- collapsing / hiding major parts of the screen
- entering something into a search box
- turning knobs on a form that draws a graph
- drag and drop ui elements without side effects on the wider application
- the above with side effects on the wider application
All of these things and more have been implemented with or without changing the URL.
The navbar in browsers may accept more (up to 4KByte in my experiments), but other 'infrastructure' where the URL needs to travel through (for instance URL shorteners) may clamp the source URL to a much shorter length.
It would have been awesome to distribute ready-to-play emulator links for home computer scene demos without hosting the data anywhere, alas it didn't work except for very small demos :)
I've used the fragment to store client-side state in a few apps, and it seems fine.
Is there some reason to use the query string rather than the fragment?
This workaround was needed when history push state did not yet exist or work across browsers. The hash hack is no longer needed, but still popular.
Does it matter at this point, for client-side state?
I think real query strings "look better", which is subjective but a more real world advantage is as follow. When you start out with a fully client-side web app (server sends empty body/div only) and use proper query strings in the client, you then later have the flexibility to add better server side rendering without any URL migration needed. Because the server can read the querystring, unlike hashes.
To reuse the example from https://antonz.org/storing-state/#boolean-value
{"search": "potatoes", "popular": true} can be serialized as ?search=potatoes&popular
A side effect of this is that if user decided to abandon our site at checkout page, they are able to go back using browser navigation with state fully restored.
Did you mean to write “very trivial” here? This is the same formatting as used when submitting forms with array and/or dictionary data, and further nesting commonly adds further brackets `like[foo][bar]=baz`. IME the querystring [0] package is great for this.
What happens when the user presses BACK.
Pagination seems acceptable, but if I go to a list page, then apply 3 filters, do I have to click "back" 3 times to leave the page? Do you just overwrite the history to allow the described 'refresh recovery' without clogging the history? Do you "debounce" sessions of filter changes within a period of time into a single "back"?
If your filters live update the results as you select them your UX will be crappy.
I believe it must have been before browser cookies was widely supported?
If I refresh the page and my state is lost, that is expected behavior to me.
If I do not like the state of the page, I can refresh the page and start over.
It is frustrating when I refresh the page and literally nothing happens, and now I need to go into the URL and delete a bunch of shit in order to refresh my state.
It is WAY more important to me to be able to quickly build any state from scratch. I do not ever want to be 10 minutes into building some specific state on your website. I do not care how well you handle it because I dont trust it to persist anyway. I do not want to trust it to persist.
Focus your energy on improving the navigation of your site or build state into the site itself. Let me save search criteria terms into a named list associated with my account if it's important. I want to be dependent on the URL for as little as possible, even indirectly.
how is being unbothered by a lack of features others claim they need a form of stockholm syndrome?