- From: Mike Wilson <mikewse@hotmail.com>
- Date: Mon, 15 Jun 2009 15:33:22 +0200
INTRODUCTION HTML5 provides a number of constructs to transfer and manage application state. In this post I attempt to classify these constructs in a consistent manner to identify what kinds of state management is taken care of, and what is not. My goal is to discuss the uncovered areas to see if we can address them with suitable additions to HTML5. DEFINITIONS State To simplify this overview I limit myself to only addressing internal state that the application stores to keep track of the user's interaction with it, and that isn't directly accessible by the user. This means f ex that hidden input fields are included in this overview (as these usually represent some internal state) but editable input fields are not (as these correspond more to page parameters than page state). I know this distinction may not be perfect, and at some point we might want to include the other parts, but I think it is good to start out with these restrictions. State can be stored in many different ways, and many different things can be regarded as state, so consider the below scenario to understand what I regard as state in this post: - a user makes some navigation action that makes the browser navigate to, and request http://host/page1 - when returning the response for page1, the server may include some state ("ServerState") to be stored in the browser through some state construct - during the lifetime of the returned page in the browser, additional state may be produced by script ("ScriptState") and stored by some other state construct - to qualify as state constructs in this overview, the constructs used to store ServerState and ScriptState above should support that the state survives the following actions: . navigating away from, and then back again, to the current session history entry in the browsing context, including scenarios where the document objects have been discarded in the meantime . page reload/refresh of the current page (this follows from the first point) (there are many other actions that could be mentioned but the above two are enough for this overview) State that survives these criteria is "real" state in the browser. Server-controlled state This is state which is created by the server application and then transmitted to the browser where it is stored, to later be transparently sent back to the server for identification or processing. As it is under server control it should not rely on script execution in the browser, so state constructs need to have a mechanism that both automatically stores the state in browser, and automatically transfers it back from browser to server when appropriate. Typically the transfer back and forth between server and browser takes place on at least every page request and response. Script-controlled state This is state created and stored by script in the browser. The preservation of state only applies to other script reading the data and any mechanism for transfer back and forth to the server is optional. Scopes State can be stored on different scopes, or contexts, to control its reach and lifetime. HTML5 offers the following scopes where a higher item on the list encloses lower items: - User agent (an application containing a collection of top-level browsing contexts) - Browsing context (has session history with a number of Documents) - Document (corresponds to one page load from server but can be associated with multiple session history entries with different navigational states) - Session history entry (a single navigational state for a Document) Apart from the different scopes, state is also kept separated by origin, to not allow different sites to interfere with each other's state. I will just assume origin is in effect for the rest of this post. User visibility For different scenarios it may, or may not, be desired to indicate the current state to the user through the browser user interface. This could f ex mean being part of the URL for bookmarkability etc. It is an advantage if the application author can choose between state constructs both with and without user interface exposure. Request type (http method) Some state constructs are unique to a certain http method. In this overview I list GET and POST methods. FEATURE TABLES Below are tables comparing properties of different state constructs. There are many alternatives to how these tables could be organized but I've tried to keep things simple and only add columns for the most important properties for this discussion. SERVER-CONTROLLED STATE Scope Visibility Request : State construct ----- ---------- ------- --------------------- user agent, invisible, GET : cookie user agent, invisible, POST : cookie browsing context, invisible, GET : - browsing context, invisible, POST : - document, invisible, GET : - document, invisible, POST : form hidden input * document, url, GET : url path/query (redir) document, url, POST : url path/query (redir) Notes: - the session history entry scope is not listed here as it is not available to server code - url-based state is only listed for Document as this isn't applicable to user agent or browsing context Cookies Cookies apply to the user agent level, which typically means all browsing contexts belonging to the same process, or in f ex Google Chrome's case, group of processes. Actually, I haven't found any good definition of the relation between user agent and browsing contexts wrt the possibility of multiple user agent instances with their own sets of browsing contexts and cookies. The cookie spec at http://tools.ietf.org/html/rfc2965 only mentions "user agent" in a singular form. Form hidden input * Hidden form data is transferred from server to browser in the response body and is transparently sent back to the server at postback. It is marked with (*) as it violates transparency on history navigation with discarded state, or on page refresh, if the initial page itself was served with POST, due to the "do you want to resubmit?" question asked by browser user interface. The resubmission question problem could be mitigated either by allowing the author control over when forms need to ask for resubmission, or by extending GET to allow for invisible state (discussed below) so PRG can be used without losing state. URL path/query (redirect) URL path/query redirects can be used to transfer (small) server state to the browser, f ex: . http://host/randomsudoku . application determines a suitable sudoku for this user and redirects to: . http://host/sudoku?no=72 Browsing context state There currently is no support for associating state with a browsing context. Many web application frameworks try to workaround this "multiple windows/tabs" problem, with mixed success. Here's a random link discussing this topic: http://www.mail-archive.com/users at myfaces.apache.org/msg50204.html Use-cases for browsing_context-oriented state constructs include distinguishing between multiple conversations in different windows/tabs, or f ex allowing the the user to be logged in on different accounts in different windows/tabs. A naive solution for this would be to add something similar to a browser_context-scoped cookie. Invisible Document state for GET requests There currently is no support for associating invisible state with a Document delivered with GET. This is also an area where web frameworks have worked around this problem, and typical workarounds are to use url-based (visible) state or to switch to POST instead. See f ex Spring Web Flow for an example on using the url (_flowExecutionId parameter): http://www.javalobby.org/articles/spring-webflow/ or JSF and ASP.NET using "view states" hidden in form posts: http://www.dotnetjohn.com/articles.aspx?articleid=71 http://books.google.com/books?id=Iv9r-CT6ZwwC&pg=PA20&source=gbs_search_r&ca d=1_1#PPA20,M1 (see "Saving and restoring state") (View state requirements is not an exact match to this topic but similar enough to deserve a mention. A typical ugly pattern seen together with this is overriding all links in a page with script, to submit the form containing the view state to ensure it is sent back to server.) Use-cases include keeping state for coordinating multiple selections over a number of steps in session history, to restore the correct selections when going back or forward in history. Examples of this is found in the second half of this article: http://magazine.redhat.com/2007/10/31/continuing-the-conversation-understand ing-seam-nested-conversations/ A naive solution for this would be to add something similar to a Document-scoped cookie. SCRIPT-CONTROLLED STATE Scope Visibility : State construct ----- ---------- --------------------- user agent, invisible : WS localStorage browsing context, invisible : window.name, WS sessionStorage document, invisible : - history entry, invisible : history state history entry, url, : url hash Notes: - url-based state is only listed for history entries within the same Document as any other url change would navigate away from the current Document with the executing script WebStorage WebStorage's localStorage and sessionStorage take care of the two first scopes. Window.name In addition, window.name is actually also a state construct that can share data between different Documents in the same browsing context. History state HTML5's History.pushState takes care of invisible state associated with history entries. URL hash Traditional hash urls http://host/page#state take care of url- visible state asociated with history entries. Document state There currently is no support for associating script state on the Document level. Any state saved in DOM or script global object will be lost on a page reload. Use cases would include single-page Ajax applications that want to store data independent of a certain history entry, but at the same time not sharing it with other page loads (Documents) of the same application in the history of the same browsing context (otherwise sessionStorage could be used). Possible solutions would be to add a new "documentStorage" to WebStorage, or to offer a History.setDocumentState method. I welcome any discussion about the missing pieces, and possible solutions, in these state construct listings. Best regards Mike Wilson
Received on Monday, 15 June 2009 06:33:22 UTC