TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

How to store your app's entire state in the url

640 pointsby escotover 2 years ago

111 comments

divbzeroover 2 years ago
App state in URL can be a good idea, but if possible I prefer readable path&#x2F;query parameters instead of unreadable base64 encoding.<p>As one comparison, this is Google Finance encoding stock chart parameters:<p><pre><code> https:&#x2F;&#x2F;www.google.com&#x2F;finance&#x2F;quote&#x2F;F:NYSE?window=5Y </code></pre> Versus Yahoo! Finance doing the same:<p><pre><code> https:&#x2F;&#x2F;finance.yahoo.com&#x2F;quote&#x2F;F&#x2F;chart?p=F#eyJpbnRlcnZhbCI6IndlZWsiLCJwZXJpb2RpY2l0eSI6MSwidGltZVVuaXQiOm51bGwsImNhbmRsZVdpZHRoIjo0LjM0ODY1OTAwMzgzMTQxNzUsImZsaXBwZWQiOmZhbHNlLCJ2b2x1bWVVbmRlcmxheSI6dHJ1ZSwiYWRqIjp0cnVlLCJjcm9zc2hhaXIiOnRydWUsImNoYXJ0VHlwZSI6ImxpbmUiLCJleHRlbmRlZCI6ZmFsc2UsIm1hcmtldFNlc3Npb25zIjp7fSwiYWdncmVnYXRpb25UeXBlIjoib2hsYyIsImNoYXJ0U2NhbGUiOiJsaW5lYXIiLCJzdHVkaWVzIjp7IuKAjHZvbCB1bmRy4oCMIjp7InR5cGUiOiJ2b2wgdW5kciIsImlucHV0cyI6eyJpZCI6IuKAjHZvbCB1bmRy4oCMIiwiZGlzcGxheSI6IuKAjHZvbCB1bmRy4oCMIn0sIm91dHB1dHMiOnsiVXAgVm9sdW1lIjoiIzAwYjA2MSIsIkRvd24gVm9sdW1lIjoiI2ZmMzMzYSJ9LCJwYW5lbCI6ImNoYXJ0IiwicGFyYW1ldGVycyI6eyJ3aWR0aEZhY3RvciI6MC40NSwiY2hhcnROYW1lIjoiY2hhcnQifX19LCJwYW5lbHMiOnsiY2hhcnQiOnsicGVyY2VudCI6MSwiZGlzcGxheSI6IkYiLCJjaGFydE5hbWUiOiJjaGFydCIsImluZGV4IjowLCJ5QXhpcyI6eyJuYW1lIjoiY2hhcnQiLCJwb3NpdGlvbiI6bnVsbH0sInlheGlzTEhTIjpbXSwieWF4aXNSSFMiOlsiY2hhcnQiLCLigIx2b2wgdW5kcuKAjCJdfX0sInNldFNwYW4iOnsibXVsdGlwbGllciI6NSwiYmFzZSI6InllYXIiLCJwZXJpb2RpY2l0eSI6eyJwZXJpb2QiOjEsImludGVydmFsIjoid2VlayJ9fSwibGluZVdpZHRoIjoyLCJzdHJpcGVkQmFja2dyb3VuZCI6dHJ1ZSwiZXZlbnRzIjp0cnVlLCJjb2xvciI6IiMwMDgxZjIiLCJzdHJpcGVkQmFja2dyb3VkIjp0cnVlLCJldmVudE1hcCI6eyJjb3Jwb3JhdGUiOnsiZGl2cyI6dHJ1ZSwic3BsaXRzIjp0cnVlfSwic2lnRGV2Ijp7fX0sImN1c3RvbVJhbmdlIjpudWxsLCJzeW1ib2xzIjpbeyJzeW1ib2wiOiJGIiwic3ltYm9sT2JqZWN0Ijp7InN5bWJvbCI6IkYiLCJxdW90ZVR5cGUiOiJFUVVJVFkiLCJleGNoYW5nZVRpbWVab25lIjoiQW1lcmljYS9OZXdfWW9yayJ9LCJwZXJpb2RpY2l0eSI6MSwiaW50ZXJ2YWwiOiJ3ZWVrIiwidGltZVVuaXQiOm51bGwsInNldFNwYW4iOnsibXVsdGlwbGllciI6NSwiYmFzZSI6InllYXIiLCJwZXJpb2RpY2l0eSI6eyJwZXJpb2QiOjEsImludGVydmFsIjoid2VlayJ9fX1dfQ-- </code></pre> In both examples, the only custom parameter is setting the time window to 5 years.
评论 #34314784 未加载
评论 #34314746 未加载
评论 #34315600 未加载
评论 #34314818 未加载
评论 #34314772 未加载
评论 #34314972 未加载
评论 #34314962 未加载
评论 #34321989 未加载
评论 #34318891 未加载
评论 #34321224 未加载
评论 #34315769 未加载
评论 #34319235 未加载
评论 #34314783 未加载
评论 #34325398 未加载
评论 #34315923 未加载
评论 #34314798 未加载
swyxover 2 years ago
This is quickly becoming a standard in apps and it really shouldnt be handrolled since its such a common requirement and easy to get wrong (between serializing&#x2F;deserializing&#x2F;unsetting states). In Svelte it is now as easy as using a store: <a href="https:&#x2F;&#x2F;github.com&#x2F;paoloricciuti&#x2F;sveltekit-search-params">https:&#x2F;&#x2F;github.com&#x2F;paoloricciuti&#x2F;sveltekit-search-params</a><p>in general i&#x27;ve been forming a thesis [0] that there is a webapp hierarchy of state that goes something like:<p>1. component state (ephemeral, lasts component lifecycle)<p>2. temp app state (in-memory, lasts the session)<p>3. durable app state (persistent, whether localstorage or indexeddb or whatever)<p>4. sharable app state (url)<p>5. individual user data (private)<p>6. team user data (shared)<p>7. global data (public)<p>and CRUD for all these states should be as easy to step down&#x2F;up as much as possible with minimal api changes as possible (probably a hard boundary between 4&#x2F;5 for authz). this makes feature development go a lot faster as you lower the cost of figuring out the right level of abstraction for a feature<p>0: relatedly, see The 5 Types of React Application State, another post that did well on HN <a href="https:&#x2F;&#x2F;twitter.com&#x2F;swyx&#x2F;status&#x2F;1351028248759726088" rel="nofollow">https:&#x2F;&#x2F;twitter.com&#x2F;swyx&#x2F;status&#x2F;1351028248759726088</a><p>btw my personal site makes fun use of it -&gt; any 404 page takes the 404&#x27;ed slug and offers it as a URL param that fills out the search bar for you to find the link that was broken, see <a href="https:&#x2F;&#x2F;www.swyx.io&#x2F;learn%20in%20public" rel="nofollow">https:&#x2F;&#x2F;www.swyx.io&#x2F;learn%20in%20public</a>
评论 #34314377 未加载
评论 #34325407 未加载
评论 #34314515 未加载
评论 #34314321 未加载
评论 #34323060 未加载
AndrewStephensover 2 years ago
This is pretty common and has a bunch of advantages, like the fact you can link to and bookmark a particular state.<p>Also, if you are careful you get undo and redo for free with the browser&#x27;s back button doing all the work for you.<p>The disadvantages are that your representation of internal state becomes part of the interface - if you ever change your app you need to deal with versioning the state so your new version can transparently handle the old state format.<p>If your app has a server component that acts on this state, be super careful about acting on it and treat it as you would any other input under user control.<p>If you app is completely client side, consider storing the state in the #fragment section of the URL. This never gets sent to the server. An example from my own site [0] - see how the fragment part of the URL changes as you select different topics.<p>There are also limits on just how much you can cram into a URL but with care you can shove a lot of state.<p>[0] <a href="https:&#x2F;&#x2F;sheep.horse&#x2F;tagcloud.html#computing" rel="nofollow">https:&#x2F;&#x2F;sheep.horse&#x2F;tagcloud.html#computing</a>
评论 #34314064 未加载
评论 #34316923 未加载
评论 #34317894 未加载
评论 #34314846 未加载
评论 #34317939 未加载
redleader55over 2 years ago
A better idea is to use the URI fragment (the string after the # sign). It has the advantage of not having a size limit, and not needing to be sent all to the backend during the request. `window.location.hash` is your friend.
评论 #34314701 未加载
评论 #34315941 未加载
评论 #34313601 未加载
评论 #34313757 未加载
评论 #34313630 未加载
评论 #34313353 未加载
评论 #34315617 未加载
评论 #34313535 未加载
评论 #34314650 未加载
评论 #34319811 未加载
评论 #34313105 未加载
评论 #34315165 未加载
Zamicolover 2 years ago
We wrote a library for storing application state in the URL. Its novel feature is using fragment query, which prevents the information from being sent to the server.<p><a href="https:&#x2F;&#x2F;github.com&#x2F;Cyphrme&#x2F;URLFormJS">https:&#x2F;&#x2F;github.com&#x2F;Cyphrme&#x2F;URLFormJS</a><p>I would love to see it get more use.<p>Here&#x27;s a small demo: <a href="https:&#x2F;&#x2F;cyphrme.github.io&#x2F;URLFormJS&#x2F;#?first_name=Bob&amp;last_name=Smith&amp;email_address=bob@something.com&amp;phone_number=1234567890&amp;subscribe_latest_news=true&amp;country_select=1:~:text=Bob" rel="nofollow">https:&#x2F;&#x2F;cyphrme.github.io&#x2F;URLFormJS&#x2F;#?first_name=Bob&amp;last_na...</a><p>See my other comment on this page for some other examples of its use.
评论 #34314363 未加载
评论 #34314505 未加载
phkahlerover 2 years ago
I did this for an Othello game back in the 90&#x27;s. The state was encoded in the URL along with the players move. It seemed weird to encode a slightly different URL for every move the player might click, but that also meant squares that were not legal moves didn&#x27;t get a URL. And that meant the mouse pointer would change when you hovered over a valid square! Another trick was to return the updated board state, but also include an automatic reload after a few seconds with the computers next move already determined. This made it look like &quot;thinking&quot; was going on when in fact it was already decided when the board updated on players move ;-) This was all in a CGI script. As others have pointed out, it also supported &quot;undo&quot; via the back button. Fun.
Ndymiumover 2 years ago
Last November I had covid and during that time I wrote a little pastebin that runs in the browser, compresses the paste data with Brotli, and puts it in the URL. It has line numbers, file naming, and syntax highlighting so it&#x27;s feature complete for my own use. Here&#x27;s a demo, but beware, the URLs are loooong: <a href="https:&#x2F;&#x2F;nicd.gitlab.io&#x2F;t&#x2F;#NhfW?Qm3F?6-&amp;22c&amp;CQZXuP+Aej5OXzXk7WPSpyN1MjAdr+PwAZltsgU&amp;3R8c8cCSUJBybp+~U7~IOktUPAS&#x2F;rXc+60kTVsWT21IwCw$r2o+Em3N5zyYc?qhE7ECJWHoSjQ8NemN8BZk_2UQ~Nf-gUr4Y&#x2F;j854zD4RK=&#x2F;QKB$qJy&amp;uNSzZiGpk3dCj0alu?CaHH9Uaqpk9kh~1so0DqHLIdmIYJ8C2gpA625pD-VDal-rkL&#x2F;egUCa&#x2F;P$2f5kdOdgipOVc?ikrRv8bT5$ADVQR7PRt$kS4TpNO9&amp;P74.xsv-ZsZVEHW6dTExkj8u1Pr3JZ=HJ7+bIx8aS6ounfMpRg=fUHqG5PYiLD9FVChk7aIb0nCMmL8K3A4VPuUDwWlO~zAta8YyiU8SGjromJ~I.edi9WoVMbp-lt1j.kydxkvLyYYRmM?N0bqbjL8P39cL~HUyi_+RW6~dsNW4c9n.sYlNN7h=aUs4jT+Mi_&amp;EtTDdlA9Qtbj_Ln1jxFGS.OsSuHYNubts_eGJ_x" rel="nofollow">https:&#x2F;&#x2F;nicd.gitlab.io&#x2F;t&#x2F;#NhfW?Qm3F?6-&amp;22c&amp;CQZXuP+Aej5OXzXk7...</a><p>I find it interesting to sometimes play around with the pasted data just to see how it compresses. Sometimes adding a character or two may cut several characters from the URL length!
评论 #34318051 未加载
评论 #34329118 未加载
评论 #34322142 未加载
bmalicoatover 2 years ago
I love stuff like this. Around 2008 or so I was working on a Java game for the T-Mobile Sidekick (aka hiptop). The platform let you register url scheme handlers so I registered &quot;drod&quot; (the game was a from-scratch port of Deadly Rooms of Death, a classic shareware game). Since the game was a 16x16 grid-based game with 3 layers, it was super efficient at expressing levels, including monsters and locks and keys, with just a limited number of bits. On my website I had &quot;DLC&quot; in the form of drod:&#x2F;&#x2F;[base64 encoded level here]. It always filled me with joy that users already downloaded the levels when they navigated to the website. Clicking the link just opened the game with the data they already had on their device.
mguervilleover 2 years ago
Isn&#x27;t this also how old school games (I&#x27;ve seen it as late as the NES I think) did allow you to save progress, you&#x27;d get a short string as your &quot;save&quot; and could just enter it to restart the game in the same state later. I love that it offers essentially unlimited &quot;saves&quot;
评论 #34313752 未加载
评论 #34313748 未加载
评论 #34314897 未加载
评论 #34313690 未加载
franciscopover 2 years ago
In React you normally create local ephemeral state like this:<p><pre><code> const [myState, setMyState] = useState(null); </code></pre> I&#x27;ve created at least 3 libraries that follow that same pattern, but instead of ephemeral the state is saved somewhere:<p><pre><code> &#x2F;&#x2F; ?firstname= const [firstName, setFirstName] = useQuery(&#x27;firstname&#x27;); &#x2F;&#x2F; localStorage const [name, setName] = useStorage(&#x27;name&#x27;); &#x2F;&#x2F; global state (that can be connected to other places) const [user, setUser] = useStore(&#x27;user&#x27;);</code></pre>
mrdoob2over 2 years ago
Made this thing in 2010. I can&#x27;t remember if I saw the trick being used in another website before or not... <a href="https:&#x2F;&#x2F;mrdoob.com&#x2F;projects&#x2F;voxels&#x2F;#A&#x2F;bnciaTraheakhacTSiahfaotaiafUscierhoShahfShahfafiWheSheUeWSfafhchhefffchhWffahherhpfXTbdUhUhUhVihShaffahfahhcfhYhaffYhahhaeeUhahhahhcdfShYhYhafhUheffdafhcjhShYfYfahfYfahfYfafhcjhYeahfShShWhfVbfdjjhaffaffaffafhafhafhahhahhahhahfahfeehhahfahfaffaffafhafhahhWhfahhWhfWffahhefXhUhehffahiaddbnfffYhcmfrfsaaiU" rel="nofollow">https:&#x2F;&#x2F;mrdoob.com&#x2F;projects&#x2F;voxels&#x2F;#A&#x2F;bnciaTraheakhacTSiahfa...</a>
escotover 2 years ago
Hey all, I made this post to show a technique that I&#x27;m using in my keyboard-centric flowchart editor [0]. I really love urls, and the power that they hold, and would love to see more apps implement little hacks like this.<p>Also, another shout out to mermaidjs and flowchart.fun for also implementing similar url-based sharing.<p>[0] <a href="https:&#x2F;&#x2F;www.knotend.com" rel="nofollow">https:&#x2F;&#x2F;www.knotend.com</a>
评论 #34312903 未加载
评论 #34326832 未加载
评论 #34313544 未加载
sidharthvover 2 years ago
I had to add compression into Mermaid live editor&#x27;s URL state as the length limit was exceeded with big diagrams.<p>Wrote this SerDe which can be extended with better algorithms in the future. <a href="https:&#x2F;&#x2F;github.com&#x2F;mermaid-js&#x2F;mermaid-live-editor&#x2F;blob&#x2F;develop&#x2F;src&#x2F;lib&#x2F;util&#x2F;serde.ts">https:&#x2F;&#x2F;github.com&#x2F;mermaid-js&#x2F;mermaid-live-editor&#x2F;blob&#x2F;devel...</a><p>Eg: <a href="https:&#x2F;&#x2F;mermaid.live&#x2F;edit#pako:eNo9kUGTnCAQhf8K1adNlesoqKiHVO3MbE7JJZNcsubACioVEQOYZHbK_76I2eUE_b3X3cW7Qau5gBp6w-YBfTs3E_Ln4ekoe_T96-ef6P7-IzrenbSajbAW_ZVuQDP7pT_symMQnO6OzApUZOhx2hr-h6cAz08XxcYxtIMIlDCKSe5n3jZVA24QSjRQ-ysXHVtG10C0Iyt-L2JqA73tPRtQ0hhtHlqnjd1Ax0Yronfqt2S9-KQnd5EvwYmzDa7NtPrxy8yZE49cejvUuxfY4vTlOrVQO7OIN9FZMv8t6l01s-mH1upN5J9Q3-Af1JiWMSY0wwXNaZniPIIr1BWO8zwnOKGkolmRrhG8BHsSU0LKskpKD3OaJV4vwkJf9jBCJhGMmnFhthnuOoeQpHW-3uqpk_1WX8zoy4Nzs60Phw3HvQ9oeY5brQ5W8oEZN_ypikOBi5JhIgpKWE4Ib5_TquxwlnacJilmsK7rK1fwoJI" rel="nofollow">https:&#x2F;&#x2F;mermaid.live&#x2F;edit#pako:eNo9kUGTnCAQhf8K1adNlesoqKiHV...</a>
kissgyorgyover 2 years ago
I did something similar, but compressed with pako to make the URL as short as possible: <a href="https:&#x2F;&#x2F;www.pokerregion.com&#x2F;?r=Y2RwYBBgYGFkcGAQYGBhZHBgEGBgYQQA" rel="nofollow">https:&#x2F;&#x2F;www.pokerregion.com&#x2F;?r=Y2RwYBBgYGFkcGAQYGBhZHBgEGBgY...</a><p>Here is the compression code: <a href="https:&#x2F;&#x2F;gist.github.com&#x2F;kissgyorgy&#x2F;39623a7d0ba2f6faafb464b72a1d412d" rel="nofollow">https:&#x2F;&#x2F;gist.github.com&#x2F;kissgyorgy&#x2F;39623a7d0ba2f6faafb464b72...</a><p>I used the properties of my data structure (multiple cards represented in a byte as bits) to represent the same data on less bytes (to avoid compressing JSON with unnecessary characters)
metahostover 2 years ago
There is a max length to URLs after which it is all wild west based on the browser implementation.<p>See: <a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;417184" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;417184</a>
moritzwarhierover 2 years ago
Great for complex apps in the browser and sharing complex save states!<p>Bad for ordinary, mundane web applications and sharable URLs!<p>Like, great for a musical step sequencer in the browser, bad for a website or HTTP service<p>OTOH, app state on websites of commercial service prodivders might be best represented by a JSON blob anyway.<p>In something like a checkout process or form submit, of course this doesn&#x27;t matter much.<p>But I prefer human-readable URLs wherever possible.<p>And I implemented a similar pattern once, too.<p>It&#x27;s a very interesting approach in intself.<p>Relevant POJO state tends to be small enough but long lists or resourcrs in a URL are not supported by most servers and not advisable.
oaieyover 2 years ago
Just do not. That or alternatively a hidden field is how asp.net WebForms did it state management 20 years ago. Worst possible idea ever.<p>Good for small scale unimportant external state management but not for your everyday web app.
评论 #34315542 未加载
评论 #34314909 未加载
ladbergover 2 years ago
I tried to do that at first with <a href="https:&#x2F;&#x2F;textshader.com" rel="nofollow">https:&#x2F;&#x2F;textshader.com</a> because the whole site is client-side and I didn&#x27;t want to bother with a backend. It didn&#x27;t really work because the state is unbounded in size, so instead I just chuck it on GitHub gists and then point to the gists. It means I don&#x27;t have to store any data myself and there&#x27;s zero recurring costs outside of the domain name... but if the site ever got popular I&#x27;d probably have to figure something else out.
评论 #34313537 未加载
EGregover 2 years ago
On a related note …<p>If you don’t want to store anything on the server, why serve the static JS and HTML? You can embed them in the URL also.<p>In that cass the URL just becomes a local file.<p>You should store the file locally, along with all the data it embeds.<p>Or you can store the files on a CDN at the edge. The problem with the latter is that people can abuse the storage.<p>Really, the Web needs to be overhauled to have a topology more like a DHT, where you only have peering agreements with a few peers, and they cache the content temporarily when it is requested a lot. So no centralized servers at all.
martini333over 2 years ago
Vuejs Playground does this. This is the url for the default tamplate:<p><a href="https:&#x2F;&#x2F;sfc.vuejs.org&#x2F;#eNo9j71uwzAMhF+F5eIWqCV0NZQA3foGXbikjpw40B9EOR0EvXspp8imu9N9OFb8TEndN4sTGp7zmgqwLVs6Ulh9irlAhWwXaLDk6GGQrwMFCnMMXMDzBQ49fx2+rHMRvmN255fhjYLRD5yARBTrkzsVKwrAXD+Ote7l1owWtbtrSFuB++jj2boDoeSEEhn9bOM7PlaN&#x2F;pTUjWOQ3bW36T9gwgl2p3uytmvCaymJJ615mfu1N1YxX7S8VN5CWb1Vlv34k+Mv2yxgwo5oFBq2P3&#x2F;sZE8=" rel="nofollow">https:&#x2F;&#x2F;sfc.vuejs.org&#x2F;#eNo9j71uwzAMhF+F5eIWqCV0NZQA3foGXbikj...</a>
Maksadbekover 2 years ago
Worth to note that it actually should use the base62 <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Base62" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Base62</a><p>It’s the same as base64 but w&#x2F;o &quot;+&quot; and &quot;?&quot; symbols.
评论 #34326771 未加载
barbazooover 2 years ago
&gt; Another great benefit is that these urls can be embedded. That means the user can put their graph on any ewb page that supports embedding. I see people typically do this with wikis like Notion, which means you can share with a team<p>This is so valuable that it can&#x27;t be overstated. Being able to store the raw data in a link WITH the visual representation, you&#x27;ll never struggle trying to find out who has the latest version.
评论 #34325138 未加载
bereligover 2 years ago
This is exactly how Shel Kaphan (first eng @ Amazon) handled the state of a shopping cart in the mid 90s. Here is him discussing some of the pitfalls: <a href="https:&#x2F;&#x2F;lists.w3.org&#x2F;Archives&#x2F;Public&#x2F;www-talk&#x2F;1995NovDec&#x2F;0202" rel="nofollow">https:&#x2F;&#x2F;lists.w3.org&#x2F;Archives&#x2F;Public&#x2F;www-talk&#x2F;1995NovDec&#x2F;020...</a>
ananthakumaranover 2 years ago
About 6 years ago I had to do this on a project. We had charts with a lot of options and we wanted them to be bookmarkable and shared between colleagues. We started with base64, soon moved to a custom encoding with version support <a href="https:&#x2F;&#x2F;github.com&#x2F;ananthakumaran&#x2F;u">https:&#x2F;&#x2F;github.com&#x2F;ananthakumaran&#x2F;u</a>
评论 #34405637 未加载
dndn1over 2 years ago
I built a quick&#x2F;wip payroll validator [0] that can read state (i.e. payroll details) from the URL.<p>The purpose in this case was to generate a QR code, the idea is this can be included in physical payslips. Then the numbers behind the calculations (tax deductions) can be validated, broken down, and understood. I&#x27;m developing more tools to these ends, via my overarching project calculang, a language for calculations [1].<p>I also have a loan&#x2F;repayment validator [2] but haven&#x27;t added this QR code feature yet.<p>Bank letters e.g. &quot;Interest rates are rising and now we want 100e more per month, every month&quot; could use a QR code to an independent validator or to see the workings behind the 100 calculation.<p>Not using this in the real world now and there are security considerations to keep in mind, but reading state from a URL facilitates the usecase: QR codes that link physical numbers to their calculation and model.<p>Implementation of payroll calculator is an Observable notebook and thankfully it neatly supports all my strict requirements as demo of this.<p>[0] <a href="https:&#x2F;&#x2F;observablehq.com&#x2F;@declann&#x2F;payroll-playground-ireland-wip" rel="nofollow">https:&#x2F;&#x2F;observablehq.com&#x2F;@declann&#x2F;payroll-playground-ireland...</a><p>+Feature tweet: <a href="https:&#x2F;&#x2F;twitter.com&#x2F;calculang&#x2F;status&#x2F;1608183731533107206" rel="nofollow">https:&#x2F;&#x2F;twitter.com&#x2F;calculang&#x2F;status&#x2F;1608183731533107206</a><p>[1] <a href="https:&#x2F;&#x2F;github.com&#x2F;calculang&#x2F;calculang">https:&#x2F;&#x2F;github.com&#x2F;calculang&#x2F;calculang</a><p>[2] <a href="https:&#x2F;&#x2F;observablehq.com&#x2F;@declann&#x2F;loan-validator-dev" rel="nofollow">https:&#x2F;&#x2F;observablehq.com&#x2F;@declann&#x2F;loan-validator-dev</a>
ecshaferover 2 years ago
What is old is new again.<p>Back before websites were &quot;Apps&quot;, you could often do exactly this (Including Authentication!) right from the url.
评论 #34315558 未加载
lol768over 2 years ago
Am I alone in thinking it&#x27;s ridiculous for an editor action to push&#x2F;pop state in browser history to allow undo&#x2F;redo? Surely this leads to substantial browser history pollution?
评论 #34314568 未加载
评论 #34315089 未加载
michaelteterover 2 years ago
As long as your users are reasonably tech-saavy this is ok. But long URLs can be problematic when sent in email for many possible reasons, such as the email client wrapping the URL and then creating a link out of just part of the original URL. The user sometimes doesn&#x27;t realize this and gets unpredictable results when trying to use the URL they &quot;saved&quot; in the email.<p>Perhaps instead, assuming the user is online, hash the json state data, then send the json+hash to the server and update the URL to URL?hash. Then the user has a much shorter URL, and the server can lookup the json state from the provided hash to resume the app at that state. As a bonus you then have versions of the data over time (either posted automatically in the background or on-demand when the user clicks Save).
jcuenodover 2 years ago
This is a useful idea when you&#x27;ve got complex nested state. The problem is changing any particular part of the state is non-trivial. I ended up making `friendly-serializer`[0] to &quot;make objects more accessible in urls.&quot;<p>The idea is that instead of a base64 string, you get something that is much easier to edit in the url bar:<p>&gt; name=John%20Doe&amp;age=42&amp;address.street=123%20Main%20Street&amp;address.city=Anytown&amp;address.state=CA&amp;address.phoneNumbers.0=123-456-7890&amp;address.phoneNumbers.1=234-567-8901<p>There&#x27;s a similar npm project to [0] that I discovered after I&#x27;d published this, but I don&#x27;t recall the name. PRs welcome.<p>[0] <a href="https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;friendly-serializer" rel="nofollow">https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;friendly-serializer</a>
评论 #34320388 未加载
评论 #34417455 未加载
anon223345over 2 years ago
I saw a $12 million app have to be essentially rewritten (at a bank)<p>The “genius dev lead who went to Princeton” kept pushing that they went to Princeton so people stopped arguing against it<p>Tried to do this securely and got pwned in the very first demo
评论 #34320186 未加载
binarymaxover 2 years ago
Shameless plug for bashfill - a fun little drawing program for making art for bash stdout: <a href="https:&#x2F;&#x2F;max.io&#x2F;bash.html?zip=eDE1eTF4MjRlMXgzeTF4MzB5MXg1ZTF4NDBlMXg0eTJ4NXc1eDd5MXg3eTF4NncyZTF4M3kyeDRtMXc3eDE5bTF3M2UxdzJ4MXkyeDE1eTF4MTllMXc0eTJ4MnkxeDI2eTF4NGUxeDR5NHgxM3c1eDE0ZTF4MTltMXc3eDEzZTF4NDBlMXg0MGUxeDdiMWMydzF4N2IxYzJ3MXgxOGUxYjF4MWIxeDFiMXgxYjFjMm0xeDNiMXgxYjF4MWIxYzJtMXgyYjF4MWIxeDFiMXgxYjF4MWIxeDFiMXgxYjF4MWIxeDFiMWUxZzFjOW0zZzFjM2cxYzNtNGcxYzRtMWIxbTFiMWcxYzNiMW0xZTFtM2M0YjFtMWIxYzhtMmcxYzViMW0xYjFnMWM0YjFtMWIxbTFnMWMxZTFjMmIxbTFiMW0xYjFtMWcxYzViMW0xYjFnMWMzbTFiMW0xYjFnMWMzYjFtMWIxbTFiMWcxYzNtMWIxZTFtMmcxYzdiMW0xYjFtMWM0bTFjMWcxYzVtMWIxZzFjMTFlMWMzYjFtMWIxbTFiMW0xYjFnMWMzYjFtMWIxbTFjMTJiMm0xYjFtMWcxYzNtMWUxYzExbTFiMWM1YjF3NWMyYjFtMWIxYzN3M2IxbTFiMW0xYzFlMWMzdzJiMWM5YjJ3Mm01YjFjM3c0bTJ3MWIxYzRlMWMydzFtMncxYjl3Mm0yeTR3MW0xYjFjMXcxbTNjMXcxYzFtMXcxYjRlMXcybTF5M3cxMG0xeTh3Mm0xYzF5MWMxeTFjMXkydzVlMXk0MA==" rel="nofollow">https:&#x2F;&#x2F;max.io&#x2F;bash.html?zip=eDE1eTF4MjRlMXgzeTF4MzB5MXg1ZTF...</a><p>...made in 2013 :) Here&#x27;s the js that runs it: <a href="https:&#x2F;&#x2F;max.io&#x2F;bash.js" rel="nofollow">https:&#x2F;&#x2F;max.io&#x2F;bash.js</a>
jsightover 2 years ago
This reminds me of ASP.Net&#x27;s viewstate feature, tbh.
tresilienceover 2 years ago
This brings to mind the concept of continuation found in Seaside Smalltalk.<p><a href="https:&#x2F;&#x2F;www.seaside.st" rel="nofollow">https:&#x2F;&#x2F;www.seaside.st</a>
EGregover 2 years ago
It’s actually difficult to do this in the UX.<p>Suppose that you have a hierarchy that was opened. Do you want to store all the hierarchy breadcrumbs in case you hit refresh, and reload all of them?<p>Furthermore, what about URLs to initiate an action from a particular context? If you refresh what should it show? It should show a dialog &#x2F; lightbox above the page, showing the form &#x2F; interface for filling out before taking this action.
评论 #34313148 未加载
threeseedover 2 years ago
This technique goes back to the late 90s where Apple WebObjects (owned by NeXT at the time) pioneered this approach in their web framework.<p><a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;WebObjects" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;WebObjects</a><p>Was quite revolutionary at the time and it also included the first (or one of the very earliest at least) SQL ORMs.
评论 #34318696 未加载
breckover 2 years ago
This is the way. Except I would never encode the data—just store state in plain text. That way you can edit urls by hand in a pinch (comes up a lot, actually). And more trustworthy and you can be sure you take your data with you.<p>I do this in all my apps. <a href="https:&#x2F;&#x2F;ohayo.computer&#x2F;" rel="nofollow">https:&#x2F;&#x2F;ohayo.computer&#x2F;</a>, <a href="https:&#x2F;&#x2F;simoji.pub&#x2F;" rel="nofollow">https:&#x2F;&#x2F;simoji.pub&#x2F;</a>, <a href="https:&#x2F;&#x2F;try.scroll.pub&#x2F;" rel="nofollow">https:&#x2F;&#x2F;try.scroll.pub&#x2F;</a>, <a href="https:&#x2F;&#x2F;jtree.treenotation.org&#x2F;designer&#x2F;" rel="nofollow">https:&#x2F;&#x2F;jtree.treenotation.org&#x2F;designer&#x2F;</a> etc.<p>At one point I also made a tiny lib to make it easier:<p><a href="https:&#x2F;&#x2F;breckyunits.com&#x2F;patch&#x2F;" rel="nofollow">https:&#x2F;&#x2F;breckyunits.com&#x2F;patch&#x2F;</a>
saghmover 2 years ago
I imagine I&#x27;m not the first one to think of this, but a little while back I wrote a toy pastebin-like webpage that stored the code being rendered directly in the URL (with base64 and gzip compression to make it a bit smaller, although it still was quite large by usual standards). My thinking was that rather than having a centralized app for this publicly available, making a small page that could be statically hosted would make it easy for people or organizations to host their own page with whatever security they need (e.g. behind a firewall or VPN) and then the links could be shared privately on Slack or whatever without a need to add functionality for determining who should have access or how long to keep the code snippet around and instead just piggyback off of the privacy of whatever channel&#x2F;DM they sent it across and how long the Slack instance is configured to retain history.<p>When I first came up with this idea, I was going to write some sort of server backend rather than just doing everything in the frontend, but once I started actually working on it, I realized that it wouldn&#x27;t really add any value and it would make it a bit more annoying for people to self-host. Since then, I&#x27;ve wondered a bit how viable &quot;static pages with state in the URL that can be easily self-hosted&quot; would be as an alternative to a desktop GUI or Electron app for more technical users. One of the nicest parts of this approach to me is that I was able to make in only a few hours one evening despite knowing only the basics of webdev from maybe 8-10 years ago and next to nothing about programming GUIs in general. This makes me think that it wouldn&#x27;t be too hard for people to fork and modify it to their own liking (e.g. changing the hard-coded style settings for rendering the code snippets), so there could be potential for an ecosystem to grow organically around something like this.<p>In case anyone is curious to take a look: <a href="https:&#x2F;&#x2F;gitlab.com&#x2F;saghm&#x2F;pastml&#x2F;" rel="nofollow">https:&#x2F;&#x2F;gitlab.com&#x2F;saghm&#x2F;pastml&#x2F;</a>
评论 #34315685 未加载
paulirishover 2 years ago
Here&#x27;s the non-psuedo code equivalent that can leverage the CompressionStream API rather than using a browserified-gzip-library (eg pako): <a href="https:&#x2F;&#x2F;github.com&#x2F;GoogleChrome&#x2F;lighthouse&#x2F;blob&#x2F;437eb4d757c52cd19994ccf80e91e872cf2f62c7&#x2F;report&#x2F;renderer&#x2F;text-encoding.js#L18-L53">https:&#x2F;&#x2F;github.com&#x2F;GoogleChrome&#x2F;lighthouse&#x2F;blob&#x2F;437eb4d757c5...</a><p>We use it in Lighthouse for the exact same purpose, a URL #hash full of state. We found that modern browsers support 10mb of data in the hash. <a href="https:&#x2F;&#x2F;github.com&#x2F;GoogleChrome&#x2F;lighthouse&#x2F;pull&#x2F;12509#discussion_r634842711">https:&#x2F;&#x2F;github.com&#x2F;GoogleChrome&#x2F;lighthouse&#x2F;pull&#x2F;12509#discus...</a>
tlavoieover 2 years ago
As usual when I see this sort of thing, I have questions around the security needs of the application. Storing all of this information on the client means that the client has to be trusted to not mess with all of this state. If it&#x27;s important, it needs to be stored and checked server-side.
评论 #34313652 未加载
评论 #34315059 未加载
nojvekover 2 years ago
Shameless plug: I made a library to encode any json as query&#x2F;hash params in a human readable manner adhering to url friendly characters.<p><a href="https:&#x2F;&#x2F;github.com&#x2F;recurrency&#x2F;urltron">https:&#x2F;&#x2F;github.com&#x2F;recurrency&#x2F;urltron</a><p>Perfect use case for storing page state in url.
noduermeover 2 years ago
I&#x27;m sorta debating the merits of various methods like this because there&#x27;s something I want to &quot;Show HN&quot; which involves browser-based analysis of CSV files... but the way I built it for myself, I just run it on a Node server that parses the file once and stores it as json and serves it when you reopen a project. So now I want to bundle the CSV&#x2F;json with then project file. But putting it all in a base64 url seems a little crazy when saving&#x2F;retrieving gzip files from the local filesystem is just as good an option. I think this is interesting as something to consider for shared projects, but probably not ideal if the main goal is to have everything run locally anyway.
stevebmarkover 2 years ago
The Typescript Playground (<a href="https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play" rel="nofollow">https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play</a>) does something similar, it gzips the contents of your code and puts it in the URL. Pretty sweet!
actually_a_dogover 2 years ago
Only about 20 years late: <a href="https:&#x2F;&#x2F;www.ics.uci.edu&#x2F;~fielding&#x2F;pubs&#x2F;dissertation&#x2F;rest_arch_style.htm" rel="nofollow">https:&#x2F;&#x2F;www.ics.uci.edu&#x2F;~fielding&#x2F;pubs&#x2F;dissertation&#x2F;rest_arc...</a>
gautamdivgiover 2 years ago
Web servers and http enabled services can limit the length of headers and url. While this can be done it runs the risk of having surprises when unknown limits are encountered. Most of these limits are buried deep in docs, not easily visible.
评论 #34316797 未加载
评论 #34320076 未加载
vesinisaover 2 years ago
This is all fun and games until the junior dev edits the code to store the user&#x27;s search history in that obfuscated appState object. The users end up sharing their URLs in public and unknowingly leaking some very private data.
brundolfover 2 years ago
Something to be careful about here is that browsers&#x2F;proxies&#x2F;etc have arbitrary length limits on URLs, and they can vary by quite a lot<p>We did this once with a web-based REPL, where you could click a button to copy a link to something you&#x27;d previously eval&#x27;d and then send that to someone else and their buffer would be preloaded with it. It was super nifty, until someone tried it with a buffer that was a few hundred lines long and at least one browser just said &quot;nope&quot;. It sounds like OP is doing some smart stuff to minimize URL length, which should help, but there&#x27;s still a limit somewhere
holdenkover 2 years ago
I did something similar using Racket&#x27;s (nee PLT scheme) web programming module ( <a href="https:&#x2F;&#x2F;www2.ccs.neu.edu&#x2F;racket&#x2F;pubs&#x2F;hosc07-sk-mf.pdf" rel="nofollow">https:&#x2F;&#x2F;www2.ccs.neu.edu&#x2F;racket&#x2F;pubs&#x2F;hosc07-sk-mf.pdf</a> ) back with an app that got on slashdot -- <a href="https:&#x2F;&#x2F;github.com&#x2F;holdenk&#x2F;web2.0collage">https:&#x2F;&#x2F;github.com&#x2F;holdenk&#x2F;web2.0collage</a><p>The theory was wonderful (yay! stateless load balancer etc.) but in practice browsers at the time were less than happy with trying to store that much state in the URL.
ohyashover 2 years ago
I love this. My website tenor.cards has been backend-free for a while thanks to the URLs. <a href="https:&#x2F;&#x2F;tenor.cards&#x2F;design_card&#x2F;?p=Rm9yJTIwdGV4dCUyMHRoYXQlMjBpcyUyMGElMjBsZW5ndGglMjBvZiUyMGElMjB0d2VldCUyQyUyMGRvJTIweW91JTIwZXZlbiUyMG5lZWQlMjB0byUyMHN0b3JlJTIwaXQlMjBpbiUyMGElMjBkYXRhYmFzZSUzRiUyMCVGMCU5RiVBNiVCOQ==&amp;ct=skew" rel="nofollow">https:&#x2F;&#x2F;tenor.cards&#x2F;design_card&#x2F;?p=Rm9yJTIwdGV4dCUyMHRoYXQlM...</a><p>I didn&#x27;t even know about window location hash, which I just learned from the other comments. Thank y&#x27;all.
jncratonover 2 years ago
I did something similar in a simple whiteboarding app that I made a while back:<p><a href="https:&#x2F;&#x2F;github.com&#x2F;jncraton&#x2F;box-line-text">https:&#x2F;&#x2F;github.com&#x2F;jncraton&#x2F;box-line-text</a><p>The data representation could probably improve in terms of readability, but I&#x27;m happy with the way it provides a concise encoding while still including the text from the document directly:<p><a href="https:&#x2F;&#x2F;box-line-text.netlify.app&#x2F;#;c2121Hello;5321;c1341Hacker+News" rel="nofollow">https:&#x2F;&#x2F;box-line-text.netlify.app&#x2F;#;c2121Hello;5321;c1341Hac...</a>!
jonny_ehover 2 years ago
Note that this could easily break or get messy as you make changes to your app. Consider either some kind of versioning indicator, or be very careful to only add fields, never changing them.
philwelchover 2 years ago
Another way to generate potentially shorter base64 strings is to use something like Python&#x27;s `struct` to store packed binary data, and then base64 encode that. Better yet, if that data payload can be generated server-side, you can also sign that data payload, which allows you to statelessly verify the data payload itself.<p>(cf. <a href="https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;struct.html" rel="nofollow">https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;struct.html</a>)
arnorhsover 2 years ago
This is an interesting approach. Should help mitigate the URL max length for larger states.<p>However as some people have pointed out it comes with a few caveats<p>- The URL is unreadable for humans<p>- You possibly end up storing things in the URL you did not intend<p>- For smaller data sets the URL actually becomes larger than the URL params equivalent<p>- You end up having to deal with version issues, possibly even URL string migrations as the code evolves<p>I&#x27;m sure there still are use cases where this makes sense, but for most applications this ends up being overly complex
debacleover 2 years ago
Congratulations, you&#x27;ve implemented ViewState from aspx.
gernbover 2 years ago
Lots of sites do this. Lately for me there&#x27;s<p><a href="https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play" rel="nofollow">https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;play</a><p>I&#x27;m mixed on it. It means it&#x27;s mostly useless for having your own list of creations because you have to manually store the URLs (PITA) and you need to store them somewhere accessible if you want to repo the UX of the site actually storing them where you can more easily access them from anywhere.
ngc6677over 2 years ago
Also this:<p><a href="https:&#x2F;&#x2F;goog.space&#x2F;?data=eyJ0eXBlIjoidGV4dCIsInZhbHVlIjoiIyBoZWxsbyBITlxuXG5XZWxjb21lIHRvIFtnb29nLnNwYWNlXShodHRwczovL2dvb2cuc3BhY2UpXG5cbi0gZG9lcyBpdCB3b3JrIGZvciB5b3U%2FXG4tIGhvdyBkbyB5byBkbz9cblxuPHN0eWxlPlxubGkge1xuICBsaXN0LXN0eWxlOiBzcXVhcmU7XG4gIGNvbG9yOiBncmVlbjtcbn1cbjwvc3R5bGU%2BIn0%3D" rel="nofollow">https:&#x2F;&#x2F;goog.space&#x2F;?data=eyJ0eXBlIjoidGV4dCIsInZhbHVlIjoiIyB...</a>
cpaover 2 years ago
This is a handy trick that I&#x27;ve used on multiple occasions. However, it may not work on some corporate networks that filter URLs with more than a certain number of characters (I&#x27;ve encountered limits of 2048 and 4096 characters).<p>The rationale being that long URLs are often suspicious and could potentially be used for SQL injection or path traversal attacks. Whether or not this is a good heuristic is left as an exercise to the reader.
mperhamover 2 years ago
I recall this technique being used in 1999. It doesn&#x27;t work well with caching proxies which key off the URL, using a Cookie header is cleaner and simpler.
评论 #34314220 未加载
twhitmoreover 2 years ago
Limited in size as URLs encounter size limits:<p><a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;417184&#x2F;768795" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;417184&#x2F;768795</a><p>I wouldn&#x27;t consider state in the URL fully general, as data can easily exceed that for many apps; but it&#x27;s a useable technique where it fits.<p>Meaningful individual parameters are preferable, but similar size limits apply either way.
tontoover 2 years ago
I always like this when the url is always copyable, but in our app, the state can get quite large. We started with base64 encoded gzip of json.stringified app state but just gets quite long. Arguably it could be reduced a little bit, but would still be hundreds-thousands of chars routinely, so we switched to using a little URL shortening service that we wrote on aws lambda+dynamodb
aplummerover 2 years ago
I do like the approach and when it works great thats fantastic - please be careful of this as an attack vector.<p>I know of at least one bank where this was exploited, because people see the base url, assume safe, and can&#x27;t read the embedded escape &#x2F; javascript in the longer part. Especially when the link is zipped into a little clickable thing and you can&#x27;t see the URL at all.
aabbcc1241over 2 years ago
Depending on how repeative the object keys are, you maybe able to save quite some spaces with compress-json [1].<p>Since the OP is using lz-string to do compression, I suppose the data should be repetitive.<p>[1] <a href="https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;compress-json" rel="nofollow">https:&#x2F;&#x2F;www.npmjs.com&#x2F;package&#x2F;compress-json</a>
tomtomistakenover 2 years ago
We are testing this on a map[0], it&#x27;s fun. When tweeting the link, the tweet and its state is added to the map. Also, map stories are possible through Twitter threads. We just implemented a draw function and are working on an implementation for external geojsons.<p>[0] <a href="https:&#x2F;&#x2F;map.decarbnow.space" rel="nofollow">https:&#x2F;&#x2F;map.decarbnow.space</a>
strongpigeonover 2 years ago
Hah, I came up with the same thing for <a href="https:&#x2F;&#x2F;fivethreeone.app&#x2F;calculator" rel="nofollow">https:&#x2F;&#x2F;fivethreeone.app&#x2F;calculator</a> .<p>The reason I did the compression (using pako as well) was that without it the URL was too long to show a preview on iMessage. I also compress the state manually myself which saved a bunch of bytes too.
评论 #34317879 未加载
评论 #34313486 未加载
benatkinover 2 years ago
This has taken off in the Vue community w&#x2F; <a href="https:&#x2F;&#x2F;sfc.vuejs.org&#x2F;" rel="nofollow">https:&#x2F;&#x2F;sfc.vuejs.org&#x2F;</a> and <a href="https:&#x2F;&#x2F;uno.antfu.me&#x2F;play&#x2F;" rel="nofollow">https:&#x2F;&#x2F;uno.antfu.me&#x2F;play&#x2F;</a> and they use the fragment so it doesn&#x27;t get sent to the HTTP server
locofocosover 2 years ago
Neat. I did this for a very basic react ratio calculator I built. My state was so basic and small, it felt fine for a toy project. Certainly a practice I would scrutinize in a production application, but it could be useful.<p><a href="https:&#x2F;&#x2F;locofocos.com&#x2F;anything-ratio-calc" rel="nofollow">https:&#x2F;&#x2F;locofocos.com&#x2F;anything-ratio-calc</a>
eatonphilover 2 years ago
While this is great for being able to send anyone a URL to a stateful page without needing a backend database, keep in mind browsers have URL length limits and they vary by browser. Compressing as mentioned in the article can help but still you want to know when you&#x27;re going to go over and figure out a plan for dealing with that.
评论 #34314598 未加载
schwartzworldover 2 years ago
I built a tic tac toe game for my daughter a while a go that stores the game state in the URL as a proof of a similar concept. <a href="https:&#x2F;&#x2F;letter-press.netlify.app&#x2F;ttt&#x2F;" rel="nofollow">https:&#x2F;&#x2F;letter-press.netlify.app&#x2F;ttt&#x2F;</a>
dzhiurgisover 2 years ago
IIRC some base64 characters need to go thru urlEncode<p><a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1374753&#x2F;passing-base64-encoded-strings-in-url" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1374753&#x2F;passing-base64-e...</a>
shepherdjerredover 2 years ago
Shinylive, which lets you create and share data science apps, takes this approach: <a href="https:&#x2F;&#x2F;shiny.rstudio.com&#x2F;py&#x2F;docs&#x2F;shinylive.html" rel="nofollow">https:&#x2F;&#x2F;shiny.rstudio.com&#x2F;py&#x2F;docs&#x2F;shinylive.html</a>
cwt137over 2 years ago
A few years ago, I worked on an app where some of the state was kept in the session and some was on the url as GET params. We ran into an issue where some browsers would only accept urls that were less than 1024 chars long. Is that still an issue today?
评论 #34315689 未加载
评论 #34315938 未加载
builwithlogicover 2 years ago
This is fine for f its public information and if thats fine then why not just add a param with a url encoded json string. Would this make the url shorter or longer? I think shorter. So why base64encode?<p>Just wondering never created an entire app around this idea
评论 #34320865 未加载
NoobNoobover 2 years ago
I too obsess over shorter URLs but I do love the idea that the whole state is just a URL. From the comments, use good enough defaults and URL shorteners where necessary, and it&#x27;s a brilliant design for a free-tier application.
ceritiumover 2 years ago
I did the same for <a href="https:&#x2F;&#x2F;markdowntable.jose.gr" rel="nofollow">https:&#x2F;&#x2F;markdowntable.jose.gr</a><p>As some comments suggest, I will move the data from the query string to the URI fragment to avoid the length limitation.
OOPManover 2 years ago
Hmmmmmm....combine this with a link shortener and you have much the same effect except the actual state gets stored elsewhere.<p>Which is totally missing the point and being intentionally daft but it is a little amusing XD
temporallobeover 2 years ago
Out of necessity for a very similar issue, I actually wrote a small Javascript utility for this that does all this automatically and uses optional symmetric encryption. Would it be against the rules to post it here?
doolsover 2 years ago
I’ve been using this hosted on my own server since it was first posted in 2013:<p><a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=5696127" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=5696127</a>
dangover 2 years ago
Related ongoing thread:<p><i>Show HN: URL Snake</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=34288577" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=34288577</a> - Jan 2023 (30 comments)
instagaryover 2 years ago
This reminded me of Xstate (<a href="https:&#x2F;&#x2F;xstate.js.org&#x2F;docs&#x2F;" rel="nofollow">https:&#x2F;&#x2F;xstate.js.org&#x2F;docs&#x2F;</a>). Their visual editor in VSCode does this.
hardwaregeekover 2 years ago
I love doing this for playgrounds! It&#x27;s so nice to be able to share a link with the code embedded. Especially if you&#x27;re giving someone a bug report and they need a minimal reproduction.
评论 #34313708 未加载
getToTheChopinover 2 years ago
It&#x27;s pretty common to do this using the URI fragment in a link.<p>For example: <a href="https:&#x2F;&#x2F;themeasureofaplan.com&#x2F;market-timing&#x2F;#initialContributionInput=20000&amp;monthlyContributionInput=1000&amp;gapToATHInput=25&amp;cashInterestRateInput=2&amp;tradingTransactionFeeInput=0&amp;minYear=1993&amp;maxYear=2023" rel="nofollow">https:&#x2F;&#x2F;themeasureofaplan.com&#x2F;market-timing&#x2F;#initialContribu...</a><p>This shows the performance of a market timing strategy on the S&amp;P500, where you invest $20,000 upfront and $1,000 per month thereafter, while only buying when the market is 25%+ away from the all-time high price (analysis from 1993 to 2023).<p>These user input variables are all directly encoded in the URL, after the # symbol.
评论 #34313953 未加载
评论 #34313921 未加载
amadeuspagelover 2 years ago
How much of a concern is the length of the URL? It doesn&#x27;t matter for bookmarks, but what about sharing? Character limits, or even just the unwieldiness of long URLs in a textarea?
manchmalscottover 2 years ago
I am pretty certain BeepBox (An online sequencer&#x2F;tracker) does this as well. It&#x27;s pretty neat to send something in progress to a friend with just a URL, no accounts needed.
jdlygaover 2 years ago
You&#x27;ve just invented video game passwords! This reminds me of transferring over my save data from Golden Sun to Golden Sun: The Lost Age by typing in a 260 character password.
withinrafaelover 2 years ago
I don&#x27;t have an opinion on this but do want to mention that LastPass does not (currently) encrypt the URL portion of its entries in the secure vault. Something to keep in mind!
generalpfover 2 years ago
I remember when WebSphere Portal Server used to do this, and the URL would exceed 4096 characters, which was the limit that IE 6 (?) would support, breaking the entire site.
评论 #34315352 未加载
jonnycomputerover 2 years ago
Why not use localStorage or sessionStorage instead of the URL?
评论 #34316176 未加载
评论 #34316356 未加载
anigbrowlover 2 years ago
It&#x27;s clever, but I hate it: it makes computing weird and inaccessible to non-technical people, and makes citations etc. needlessly difficult to manage.
paxysover 2 years ago
Base 64 is probably not the best encoding for this, since the URL allows for a wider range of characters. You can be more efficient by using them as well.
评论 #34315071 未加载
surumeover 2 years ago
Just thinking - are there any security implications to this? Could sensitive data accidentally get added to the URL and then get intercepted?
评论 #34323522 未加载
m00dyover 2 years ago
Another one would be passing ipfs hash in the url
kevinfiolover 2 years ago
My favorite example of this is flems: <a href="https:&#x2F;&#x2F;flems.io&#x2F;" rel="nofollow">https:&#x2F;&#x2F;flems.io&#x2F;</a>
a-dubover 2 years ago
doing something like this means you have to pay attention to a few things:<p>* back&#x2F;forward button behavior<p>* cache behavior<p>* bookmarks over time<p>surprising there&#x27;s no discussion of it.
actinium226over 2 years ago
This is really cool, both the state-in-url and the app itself.<p>Just wondering, how long did it take you to put the app together?
评论 #34320850 未加载
jwilliamsover 2 years ago
Not necessarily mandatory - but I&#x27;d also recommend a stable sort on the keys prior to `stringify`.
quickthrower2over 2 years ago
Since it is ephemeral, local storage is probably fine? Feels like a better solution.
rickreynoldssfover 2 years ago
Your SEO guy is going to throttle you if you even consider thinking about doing this.
MutableLambdaover 2 years ago
But it was done already in widely known in narrow circles PlantUML years ago?
pdntspaover 2 years ago
The early 2000&#x27;s called, they want their ASP pages and IIS license back
jwoglomover 2 years ago
Like some other commenters mentioned, this is a cool idea, however by storing JSON data inside base64, the length of the URL blows up very quickly as you start storing more state.<p>While technically URLs have no formal length limit, various sources suggest that URLs with more than around 2,048 characters start causing issues in browsers, and around 8,196 start causing issues in CDNs (<a href="https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;417184" rel="nofollow">https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;417184</a>). You can work around this partially by not storing this state information in the query string (path&#x2F;to?&lt;state&gt;) and instead using a hash string (path&#x2F;to#&lt;state&gt;), and then extract that data in JavaScript such that it&#x27;s not sent to the server at all.<p>IMO, the canonical way to solve this problem is using protocol buffers, which you can then serialize into a much smaller number of bytes, which is then base64 encoded. For example, as mentioned in another comment in this thread (<a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=34314578" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=34314578</a>), Yahoo Finance has a 1,616 character-long URL with 1,572 characters of base64-encoded JSON state:<p>&gt; {&quot;interval&quot;:&quot;week&quot;,&quot;periodicity&quot;:1,&quot;timeUnit&quot;:null,&quot;candleWidth&quot;:4.3486590038314175,&quot;flipped&quot;:false,&quot;volumeUnderlay&quot;:true,&quot;adj&quot;:true,&quot;crosshair&quot;:true,&quot;chartType&quot;:&quot;line&quot;,&quot;extended&quot;:false,&quot;marketSessions&quot;:{},&quot;aggregationType&quot;:&quot;ohlc&quot;,&quot;chartScale&quot;:&quot;linear&quot;,&quot;studies&quot;:{&quot; vol undr &quot;:{&quot;type&quot;:&quot;vol undr&quot;,&quot;inputs&quot;:{&quot;id&quot;:&quot; vol undr &quot;,&quot;display&quot;:&quot; vol undr &quot;},&quot;outputs&quot;:{&quot;Up Volume&quot;:&quot;#00b061&quot;,&quot;Down Volume&quot;:&quot;#ff333a&quot;},&quot;panel&quot;:&quot;chart&quot;,&quot;parameters&quot;:{&quot;widthFactor&quot;:0.45,&quot;chartName&quot;:&quot;chart&quot;}}},&quot;panels&quot;:{&quot;chart&quot;:{&quot;percent&quot;:1,&quot;display&quot;:&quot;F&quot;,&quot;chartName&quot;:&quot;chart&quot;,&quot;index&quot;:0,&quot;yAxis&quot;:{&quot;name&quot;:&quot;chart&quot;,&quot;position&quot;:null},&quot;yaxisLHS&quot;:[],&quot;yaxisRHS&quot;:[&quot;chart&quot;,&quot; vol undr &quot;]}},&quot;setSpan&quot;:{&quot;multiplier&quot;:5,&quot;base&quot;:&quot;year&quot;,&quot;periodicity&quot;:{&quot;period&quot;:1,&quot;interval&quot;:&quot;week&quot;}},&quot;lineWidth&quot;:2,&quot;stripedBackground&quot;:true,&quot;events&quot;:true,&quot;color&quot;:&quot;#0081f2&quot;,&quot;stripedBackgroud&quot;:true,&quot;eventMap&quot;:{&quot;corporate&quot;:{&quot;divs&quot;:true,&quot;splits&quot;:true},&quot;sigDev&quot;:{}},&quot;customRange&quot;:null,&quot;symbols&quot;:[{&quot;symbol&quot;:&quot;F&quot;,&quot;symbolObject&quot;:{&quot;symbol&quot;:&quot;F&quot;,&quot;quoteType&quot;:&quot;EQUITY&quot;,&quot;exchangeTimeZone&quot;:&quot;America&#x2F;New_York&quot;},&quot;periodicity&quot;:1,&quot;interval&quot;:&quot;week&quot;,&quot;timeUnit&quot;:null,&quot;setSpan&quot;:{&quot;multiplier&quot;:5,&quot;base&quot;:&quot;year&quot;,&quot;periodicity&quot;:{&quot;period&quot;:1,&quot;interval&quot;:&quot;week&quot;}}}]}<p>The un-base64&#x27;d JSON dictionary is 1,162 characters long, 569 of which is composed of just the key names (48 percent!), and most of the remaining fields likely contain their default value. If this was instead encoded in protobuf, the key names wouldn&#x27;t need to be included, since fields are referenced by their field ID, and default field values would take up little-to-no space since when the default value is present it isn&#x27;t encoded into the structure. I presume that, if done efficiently, you could likely make an equivalent representation in protobuf that is 1&#x2F;4th or even 1&#x2F;8th the size. You also get, for better or for worse, what is essentially obfuscation for free (yes, you can read out the packed format, but without an equivalent protobuf struct definition it&#x27;s still hard to tell what field is which, and the entire operation becomes much more labor-intensive).
评论 #34315901 未加载
zengidover 2 years ago
relevant to mention the new tan-stack router that does this: <a href="https:&#x2F;&#x2F;tanstack.com&#x2F;router&#x2F;v1" rel="nofollow">https:&#x2F;&#x2F;tanstack.com&#x2F;router&#x2F;v1</a>
vqt123over 2 years ago
i do this on a site i threw together to annotate youtube videos with timestamps<p><a href="https:&#x2F;&#x2F;youtubenotes.com&#x2F;" rel="nofollow">https:&#x2F;&#x2F;youtubenotes.com&#x2F;</a><p>i used sveltekit and vercel
redbar0nover 2 years ago
&gt; Since I update it on every graph edit, I get something major for free -- undo&#x2F;redo. The browser&#x27;s history stack becomes my undo&#x2F;redo functionality.<p>A pet peeve of mine is that webapps shouldn’t hijack the browsers default functionality, here being back&#x2F;forward that should refer to pages, not mutations of the same page.<p>Ideally, one would have a separate undo&#x2F;redo button on the page for page or url mutations (which should always be in sync). But mutating the URL shouldn’t be done by pushing to the browser history stack, or if pushing one ought to remember to pop the current entry first so the result is a single mutated page on the history stack.
评论 #34320753 未加载
jerryzhover 2 years ago
one problem to me is that I run a script remove parameter in url(for tracker) ofc I can set a whitelist but it is a issue i consider
chrismsimpsonover 2 years ago
ASP.NET WebForms did this and it was horrible.
zelphirkaltover 2 years ago
Racket does this in its web framework and docs.
867-5309over 2 years ago
I&#x27;m just getting a 414 Error
评论 #34320868 未加载
dietmtnviewover 2 years ago
please don&#x27;t do this, especially if you work with map coordinates.
12311231231over 2 years ago
In other words, tracking
zX41ZdbWover 2 years ago
I&#x27;m successfully* using it in a few personal projects:<p>ClickHouse Playground: <a href="https:&#x2F;&#x2F;play.clickhouse.com&#x2F;play?user=play#U0VMRUNUIDE=" rel="nofollow">https:&#x2F;&#x2F;play.clickhouse.com&#x2F;play?user=play#U0VMRUNUIDE=</a> ClickHouse Dashboards: <a href="https:&#x2F;&#x2F;sql.clickhouse.com&#x2F;dashboard#eyJob3N0IjoiaHR0cHM6Ly9zcWwuY2xpY2tob3VzZS5jb20iLCJ1c2VyIjoicGxheSIsInF1ZXJpZXMiOlt7InRpdGxlIjoiQ2xpY2tIb3VzZSIsInF1ZXJ5IjoiU0VMRUNUIHRvTW9uZGF5KHRpbWUpOjpEYXRlVGltZTo6SU5ULCBzdW0oaGl0cykgRlJPTSB3aWtpc3RhdCBXSEVSRSBwYXRoID0gJ0NsaWNrSG91c2UnIEdST1VQIEJZIDEgT1JERVIgQlkgMSBGT1JNQVQgSlNPTkNvbXBhY3RDb2x1bW5zIn0seyJ0aXRsZSI6Ik15U1FMIiwicXVlcnkiOiJTRUxFQ1QgdG9Nb25kYXkodGltZSk6OkRhdGVUaW1lOjpJTlQsIHN1bShoaXRzKSBGUk9NIHdpa2lzdGF0IFdIRVJFIHBhdGggPSAnTXlTUUwnIEdST1VQIEJZIDEgT1JERVIgQlkgMSBGT1JNQVQgSlNPTkNvbXBhY3RDb2x1bW5zIn0seyJ0aXRsZSI6IlBvc3RncmVTUUwiLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgc3VtKGhpdHMpIEZST00gd2lraXN0YXQgV0hFUkUgcGF0aCA9ICdQb3N0Z3JlU1FMJyBHUk9VUCBCWSAxIE9SREVSIEJZIDEgRk9STUFUIEpTT05Db21wYWN0Q29sdW1ucyJ9LHsidGl0bGUiOiJFbGFzdGljc2VhcmNoIiwicXVlcnkiOiJTRUxFQ1QgdG9Nb25kYXkodGltZSk6OkRhdGVUaW1lOjpJTlQsIHN1bShoaXRzKSBGUk9NIHdpa2lzdGF0IFdIRVJFIHBhdGggPSAnRWxhc3RpY3NlYXJjaCcgR1JPVVAgQlkgMSBPUkRFUiBCWSAxIEZPUk1BVCBKU09OQ29tcGFjdENvbHVtbnMifSx7InRpdGxlIjoiUmVkaXMiLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgc3VtKGhpdHMpIEZST00gd2lraXN0YXQgV0hFUkUgcGF0aCA9ICdSZWRpcycgR1JPVVAgQlkgMSBPUkRFUiBCWSAxIEZPUk1BVCBKU09OQ29tcGFjdENvbHVtbnMifSx7InRpdGxlIjoiQmlnUXVlcnkiLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgc3VtKGhpdHMpIEZST00gd2lraXN0YXQgV0hFUkUgcGF0aCA9ICdCaWdRdWVyeScgR1JPVVAgQlkgMSBPUkRFUiBCWSAxIEZPUk1BVCBKU09OQ29tcGFjdENvbHVtbnMifSx7InRpdGxlIjoiSGFkb29wIiwicXVlcnkiOiJTRUxFQ1QgdG9Nb25kYXkodGltZSk6OkRhdGVUaW1lOjpJTlQsIHN1bShoaXRzKSBGUk9NIHdpa2lzdGF0IFdIRVJFIHBhdGggPSAnQXBhY2hlX0hhZG9vcCcgR1JPVVAgQlkgMSBPUkRFUiBCWSAxIEZPUk1BVCBKU09OQ29tcGFjdENvbHVtbnMifSx7InRpdGxlIjoiU3BhcmsiLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgc3VtKGhpdHMpIEZST00gd2lraXN0YXQgV0hFUkUgcGF0aCA9ICdBcGFjaGVfU3BhcmsnIEdST1VQIEJZIDEgT1JERVIgQlkgMSBGT1JNQVQgSlNPTkNvbXBhY3RDb2x1bW5zIn0seyJ0aXRsZSI6IlNRTCIsInF1ZXJ5IjoiU0VMRUNUIHRvTW9uZGF5KHRpbWUpOjpEYXRlVGltZTo6SU5ULCBzdW0oaGl0cykgRlJPTSB3aWtpc3RhdCBXSEVSRSBwYXRoID0gJ1NRTCcgR1JPVVAgQlkgMSBPUkRFUiBCWSAxIEZPUk1BVCBKU09OQ29tcGFjdENvbHVtbnMifSx7InRpdGxlIjoiT3JhY2xlIiwicXVlcnkiOiJTRUxFQ1QgdG9Nb25kYXkodGltZSk6OkRhdGVUaW1lOjpJTlQsIHN1bShoaXRzKSBGUk9NIHdpa2lzdGF0IFdIRVJFIHBhdGggPSAnT3JhY2xlX0RhdGFiYXNlJyBHUk9VUCBCWSAxIE9SREVSIEJZIDEgRk9STUFUIEpTT05Db21wYWN0Q29sdW1ucyJ9LHsidGl0bGUiOiJEdWNrREIiLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgc3VtKGhpdHMpIEZST00gd2lraXN0YXQgV0hFUkUgcGF0aCA9ICdEdWNrREInIEdST1VQIEJZIDEgT1JERVIgQlkgMSBGT1JNQVQgSlNPTkNvbXBhY3RDb2x1bW5zIn0seyJ0aXRsZSI6IlNpbmdsZVN0b3JlIiwicXVlcnkiOiJTRUxFQ1QgdG9Nb25kYXkodGltZSk6OkRhdGVUaW1lOjpJTlQsIHN1bShoaXRzKSBGUk9NIHdpa2lzdGF0IFdIRVJFIHBhdGggSU4gKCdNZW1TUUwnLCAnU2luZ2xlU3RvcmUnKSBHUk9VUCBCWSAxIE9SREVSIEJZIDEgRk9STUFUIEpTT05Db21wYWN0Q29sdW1ucyJ9LHsidGl0bGUiOiJCaWcgRGF0YSIsInF1ZXJ5IjoiU0VMRUNUIHRvTW9uZGF5KHRpbWUpOjpEYXRlVGltZTo6SU5ULCBzdW0oaGl0cykgRlJPTSB3aWtpc3RhdCBXSEVSRSBwYXRoID0gJ0JpZ19EYXRhJyBHUk9VUCBCWSAxIE9SREVSIEJZIDEgRk9STUFUIEpTT05Db21wYWN0Q29sdW1ucyJ9LHsidGl0bGUiOiJHcmVlbnBsdW0iLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgc3VtKGhpdHMpIEZST00gd2lraXN0YXQgV0hFUkUgcGF0aCA9ICdHcmVlbnBsdW0nIEdST1VQIEJZIDEgT1JERVIgQlkgMSBGT1JNQVQgSlNPTkNvbXBhY3RDb2x1bW5zIn0seyJ0aXRsZSI6IlRpREIiLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgc3VtKGhpdHMpIEZST00gd2lraXN0YXQgV0hFUkUgcGF0aCA9ICdUaURCJyBHUk9VUCBCWSAxIE9SREVSIEJZIDEgRk9STUFUIEpTT05Db21wYWN0Q29sdW1ucyJ9LHsidGl0bGUiOiJTbm93Zmxha2UiLCJxdWVyeSI6IlNFTEVDVCB0b01vbmRheSh0aW1lKTo6RGF0ZVRpbWU6OklOVCwgbGVhc3QoMjAwMDAsIHN1bShoaXRzKSkgRlJPTSB3aWtpc3RhdCBXSEVSRSBwYXRoID0gJ1Nub3dmbGFrZV9JbmMuJyBHUk9VUCBCWSAxIE9SREVSIEJZIDEgRk9STUFUIEpTT05Db21wYWN0Q29sdW1ucyJ9XSwicGFyYW1zIjp7fX0=" rel="nofollow">https:&#x2F;&#x2F;sql.clickhouse.com&#x2F;dashboard#eyJob3N0IjoiaHR0cHM6Ly9...</a><p>The second example shows you why it is not an entirely good idea. The second link cannot be posted in Slack and Google Meet, so I have to use an URL shortener...<p>Luckily I have it in my disposal: <a href="https:&#x2F;&#x2F;pastila.nl&#x2F;" rel="nofollow">https:&#x2F;&#x2F;pastila.nl&#x2F;</a> Example: <a href="https:&#x2F;&#x2F;pastila.nl&#x2F;?02a0d469&#x2F;8f49f7e4406bd4fbc0e7b142c470dfb0.link" rel="nofollow">https:&#x2F;&#x2F;pastila.nl&#x2F;?02a0d469&#x2F;8f49f7e4406bd4fbc0e7b142c470dfb...</a>
IYashaover 2 years ago
I&#x27;m not into web &quot;programming&quot;, but do people really have to abndon binary data storage these days? I think compressing more informaiton produces still more information. While JSON is by no means as heavy as, for example, XML, it&#x27;s far heavier than just array of int graph[x][y];
评论 #34314106 未加载
评论 #34314080 未加载
评论 #34319251 未加载
评论 #34315572 未加载
devmunchiesover 2 years ago
Seems like it could be better to store the state in a database and create a unique, short ID that goes in the URL, especially if your doing server rendering (like SSR react or HTMX, or rails&#x2F;Django)<p>&gt; I also didn&#x27;t want to store anything on the backend (at least for the free tier).<p>You can make the state unique in the DB by a user cookie ID and then upsert the state which will overwrite older state with the latest state. Then you only have 1 record per free user. Remove record that haven’t been modified in 30 days and you don’t have much overhead. Just off the cuff thinking.
评论 #34313719 未加载
评论 #34314241 未加载