Created
July 20, 2017 20:58
-
-
Save reddraggone9/cc33248f7a3a68aef6b2a45e4dd117a6 to your computer and use it in GitHub Desktop.
Post/Redirect/Get vs window.history.replaceState
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "rocket-post-redirect" | |
version = "0.1.0" | |
authors = ["reddraggone9 <cljenkins9@gmail.com>"] | |
[dependencies] | |
rocket = "0.3.0" | |
rocket_codegen = "0.3.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! A common pattern in web development has the server issue a [redirect after receiving a form | |
//! submission][0]. This is primarily intended to prevent refreshing the page from triggering a | |
//! scary browser dialog. However, it would appear that there is another option. Instead of | |
//! performing a redirect, the server could respond directly with the contents of the page it would | |
//! have redirected to and a bit of JavaScript which uses the history API to change the URL. This | |
//! gist compares the two approaches. | |
//! | |
//! [0]: https://en.wikipedia.org/wiki/Post/Redirect/Get | |
//! | |
//! Based on testing in Firefox, both methods: | |
//! | |
//! - don't resubmit the form if you refresh the page. | |
//! - send a request to `/get-after-redirect` when you refresh the page. | |
//! - show `/` followed by `/get-after-redirect` in global history. | |
//! - result in the back button returning to `/`. Going forward from that page | |
//! returns you to `/get-after-redirect`, though a get request is only issued in | |
//! the window.history case. | |
//! - show `/get-after-redirect` in the URL bar after form submission. Bookmarking | |
//! the page also works correctly. | |
//! | |
//! ## Downsides ## | |
//! | |
//! ### Post/Redirect/Get ### | |
//! - Requires an extra round trip | |
//! - Requires the server to store data (e.g. flashes) between requests. Rocket can store flash | |
//! strings in a cookie, but this has its own problems (e.g. has to be serialized to a string, | |
//! cookie size limitations, avoidable data transfer both to and from the client, needs crypto | |
//! to trust it). | |
//! | |
//! ### window.history ### | |
//! - Requires JavaScript | |
//! - Post handler must be able to "forward" to the other handler | |
//! - Going around HTTP like this feels blasphemous | |
#![feature(plugin)] | |
#![plugin(rocket_codegen)] | |
extern crate rocket; | |
use rocket::response::Redirect; | |
use rocket::response::content::Html; | |
fn main() { | |
rocket::ignite() | |
.mount("/", routes![ | |
index, | |
post_and_redirect, | |
get_after_redirect, | |
replace_state, | |
]) | |
.launch(); | |
} | |
#[get("/")] | |
fn index() -> Html<&'static str> { | |
Html(r#" | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
</head> | |
<body> | |
<form method="post"> | |
<button formaction="/post-and-redirect"> | |
POST with a redirect to update URL | |
</button> | |
<button formaction="/replace-state"> | |
POST with JavaScript to update URL | |
</button> | |
</form> | |
</body> | |
</html> | |
"#) | |
} | |
#[post("/post-and-redirect")] | |
fn post_and_redirect() -> Redirect { | |
Redirect::to("/get-after-redirect") | |
} | |
#[get("/get-after-redirect")] | |
fn get_after_redirect() -> Html<String> { | |
redirect_success(None) | |
} | |
#[post("/replace-state")] | |
fn replace_state() -> Html<String> { | |
// Upon reflection, I suppose there wouldn't be any harm in including this in the desired page | |
// unconditionally. | |
redirect_success(Some(r#" | |
<script>window.history.replaceState(null, "", "/get-after-redirect")</script> | |
"#)) | |
} | |
fn redirect_success(script: Option<&str>) -> Html<String> { | |
Html(format!(r#" | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
</head> | |
<body> | |
{}<p>Redirect successful.</p> | |
</body> | |
</html> | |
"#, script.unwrap_or(""))) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment