48

I am having a very hard time understanding the exact process of "post/redirect/get".

I have combed through this site and the web for several hours and cannot find anything other than "here's the concept".

How to understand the post/redirect/get pattern?

Andrew
  • 18,680
  • 13
  • 103
  • 118
whatdafrak
  • 561
  • 1
  • 6
  • 10
  • Did you have a specific question about it? It actually is pretty simple once you use it a bit, you can dig into it if you want. [This description](http://stevenclark.com.au/2008/01/12/get-vs-post-for-the-beginner/) looks pretty good. – Christian May 31 '12 at 04:00
  • 1
    @ChristianVarga Is that the right link? At first glance, it doesn't look like that article actually addresses [PRG](http://en.wikipedia.org/wiki/Post/Redirect/Get). – Wiseguy May 31 '12 at 04:02
  • Oh, no it's not applicable. I didn't read the question properly (lucky I didn't answer it). – Christian May 31 '12 at 04:04
  • Hey. Do you imply the "Post/Redirect/Get" web development design pattern that prevents duplicate form submissions? – verisimilitude May 31 '12 at 04:50
  • @veris Yes the prevent duplicate submission. – whatdafrak May 31 '12 at 05:58
  • 1
    If you want clean URLs (not littered with unnecessary get params), you can either use Post/Redirect/Cookie pattern or Post/Redirect/Session pattern. The idea is the same, but you're using cookie or session to store and fetch the params. – ADTC Dec 08 '16 at 17:50

5 Answers5

100

Wikipedia explains this so well!

The Problem

The Problem

The Solution

The Solution

MasterMastic
  • 20,711
  • 12
  • 68
  • 90
  • 28
    Well, this graphic it's even more clear than reading tons of text. – Fabián Oct 07 '13 at 21:48
  • Tell me something, what happens when the user refreshes or hits 'submit' again before the server's 3xx response reaches it? – Vaibhav May 27 '15 at 15:30
  • 1
    @Vaibhav Yeah, that's something the PRG pattern can't solve, you really will get duplicated POSTs. If you run into this problem, see [this](http://stackoverflow.com/q/16814157) for more information. I would use the option in [this answer](http://stackoverflow.com/a/21845938/825637) by rogueleaderr. – MasterMastic May 27 '15 at 20:05
  • @IdahoB I've never encountered this behavior from any browser and if you look up the problem of duplicate POSTs it looks like the rest of the internet hasn't either; where are you getting this from? I think you're right if the browser actually managed to get the 3xx response. But if it didn't and you refresh, the refresh is not queued, you just reload the same page and the browser drops the now-irrelevant 3xx response. – MasterMastic Aug 28 '20 at 14:11
35

As you may know from your research, POST-redirect-GET looks like this:

  • The client gets a page with a form.
  • The form POSTs to the server.
  • The server performs the action, and then redirects to another page.
  • The client follows the redirect.

For example, say we have this structure of the website:

  • /posts (shows a list of posts and a link to "add post")
    • /<id> (view a particular post)
    • /create (if requested with the GET method, returns a form posting to itself; if it's a POST request, creates the post and redirects to the /<id> endpoint)

/posts itself isn't really relevant to this particular pattern, so I'll leave it out.

/posts/<id> might be implemented like this:

  • Find the post with that ID in the database.
  • Render a template with the content of that post.

/posts/create might be implemented like this:

  • If the request is a GET request:
    • Show an empty form with the target set to itself and the method set to POST.
  • If the request is a POST request:
    • Validate the fields.
    • If there are invalid fields, show the form again with errors indicated.
    • Otherwise, if all fields are valid:
      • Add the post to the database.
      • Redirect to /posts/<id> (where <id> is returned from the call to the database)
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • I'm pretty new with php and sessions so I had a hard time relating to that example. All I am trying to do is prevent the browser from displaying "resubmit error" when I go back to my search results. The user searches the database using a form. The next page queries the database using the users info and they can click on the result and it will take them to a third page that uses the id of the result in a session variable to load info for that result. But when I click back to the results page, I get the error and everything online says I need to do this redirect thing and I'm just not getting it – whatdafrak May 31 '12 at 04:37
  • @whatdafrak: Search pages don't modify anything, so it would probably make more sense for it to be a `GET` request (unless there's a ton of data in the request, in which case it becomes more complex). – icktoofay May 31 '12 at 04:43
  • 2
    @whatdafrak: Not always. `POST` is used for actions that modify things. `GET` is used for pages that just display things, but don't modify any information. – icktoofay May 31 '12 at 05:24
  • I tried the GET method and it does exactly what I want and I understand now that GET should not be used with sensitive information so it's fine for my purpose. Thanks. I'm still frustrated b/c I don't understand how to use the PRG method but maybe I'm getting ahead of myself. I suppose I'll cross that bridge if/when I get there and hope I have a much better understanding of what I'm doing. ED: By "doing exactly what I want", I can go back and not get the "resubmit" error. – whatdafrak May 31 '12 at 05:54
11

I'll try explaining it. Maybe the different perspective does the trick for you.

With PRG the browser ends up making two requests. The first request is a POST request and is typically used to modify data. The server responds with a Location header in the response and no HTML in the body. This causes the browser to be redirected to a new URL. The browser then makes a GET request to the new URL which responds with HTML content which the browser renders.

I'll try to explain why PRG should be used. The GET method is never supposed to modify data. When a user clicks a link the browser or proxy server may return a cached response and not send the request to the server; this means the data wasn't modified when you wanted it to be modified. Also, a POST request shouldn't be used to return data because if the user wants to just get a fresh copy of the data they're forced to re-execute the request which will make the server modify the data again. This is why the browser will give you that vague dialog asking you if you are sure you want to re-send the request and possibly modify data a second time or send an e-mail a second time.

PRG is a combination of POST and GET that uses each for what they are intended to be used for.

Sarel Botha
  • 12,419
  • 7
  • 54
  • 59
  • I think I understand the concept, just not the execution. I have a search.php that takes input from a form and uses POST to submit it to results.php, which takes the input and queries it in a database. I've changed my form POST to a redirect page that works and redirects to the results.php page. But what do I need to change in my results.php file to get the variables I was passing using POST? How do those variables get passed from the form page, through the redirect page, and to the results page. And how do I access them? – whatdafrak May 31 '12 at 04:07
  • You have two options. 1. Use query parameters appended to the URL. 2. Store the data in the session. 1 is better but sometimes not practical. 2 is easier but you can make a mess if you're not careful and also use more memory on the server than you need to. – Sarel Botha May 31 '12 at 04:09
  • so on the redirect page, do I need to add `session_start();` in my redirect page to pass the variables? Do I have to retrieve the variables from the form page in my redirect page using the `$_POST` or do they just automatically stay alive? – whatdafrak May 31 '12 at 04:22
5

Just so people can see a code example (this is using express):

app.post('/data', function(req, res) {
  data = req.body;  //do stuff with data
  res.redirect('public/db.html');
});

So to clarify, it instantly refreshes the webpage and so on refresh of that webpage (e.g. if you updated an element on it) it won't repost the form data.

My code used to look like this:

app.post('/data', function(req, res) {
   data = req.body;
   res.sendFile('public/db.html');
});

So here the response is sending the html file at the /data address. So in the address bar, after pressing the submit button it would say for me: localhost:8080/data. But this means that on refresh of that page, if you have just submitted the form, it will submit it again. And you don't want the same form submitted twice in your database. So redirecting it to the webpage (res.redirect) instead of sending the file (res.sendFile) , stops the resubmission of that form.

imatwork
  • 523
  • 6
  • 16
1

It is all a matter of concept, there is no much more to understand :

  • POST is for the client to send data to the server
  • GET is for the client to request data from the server

So, conceptually, there is no sense for the server to answer with a resource data on a POST request, that's why there is a redirection to the (usually) same resource that has been created/updated. So, if POST is successful, the server opiniates that the client would want to fetch the fresh data, thus informing it to make a GET on it.

challet
  • 870
  • 9
  • 21