54

I want to redirect from one URL request to another 'POST' request, like this:

var app = require('express')();

app.get('/', function(req, res) {
  res.redirect('/test');
});

app.post('/test', function(req, res) {
  res.send('/test page');
});

app.listen(3000, function() {
  console.log('listenning on port:3000');
});

However, I can't redirect to '/test' page because it is a POST request.
So what should I do to make the redirection work, keeping the '/test' request POST?

ldg
  • 9,112
  • 2
  • 29
  • 44
neolicd
  • 1,009
  • 2
  • 11
  • 14
  • I am a bit confused by the term 'page' are you looking at redirecting from 1 endpoint to another? Example `/` {GET} request to `/test` {POST} – Samuel Toh Aug 07 '16 at 01:35
  • sorry for the confusion. what I mean is redirecting from 'localhost:3000/' to 'localhost:3000/test' – neolicd Aug 07 '16 at 01:42

5 Answers5

94

You can do this:

app.post('/', function(req, res) {
  res.redirect(307, '/test');
});

Which will preserve the send method.

For reference, the 307 http code spec is:

307 Temporary Redirect (since HTTP/1.1) In this occasion, the request should be repeated with another URI, but future requests can still use the original URI.2 In contrast to 303, the request method should not be changed when reissuing the original request. For instance, a POST request must be repeated using another POST request.

For more info, see: http://www.alanflavell.org.uk/www/post-redirect.html

ldg
  • 9,112
  • 2
  • 29
  • 44
  • got it. So I just can't redirect to app.post('/test') if I use app.get('/'), right? – neolicd Aug 07 '16 at 02:52
  • 1
    Not with a standard http redirect, you would need to set up some kind of proxy. – ldg Aug 07 '16 at 03:14
  • 2
    This solution forces another browser request. Server instructs browser, browser then makes another request. This is a roundabout method. Anyway i can redirect within Express directly to avoid having to go all the way to browser to make a request ? – Koder Mar 13 '17 at 13:28
  • 1
    @Koder - if you're doing it within Express/Node (without changing the URL) it's not really a redirect, so as mentioned you could use a proxy. If you have specific questions, it would probably be best to ask a new question and provide the specifics of your situation. – ldg Mar 14 '17 at 22:46
  • @Koder - if you indend the endpoint to be processed within your server - you can re-route internally - i.e re-enter the router. – Radagast the Brown Jan 09 '18 at 09:33
  • Making root ('/') as post type stops get request on root. So, I find sending a autosubmit hidden form useful. https://stackoverflow.com/a/35353805/6712094 – Ajay Sep 16 '20 at 05:01
  • Thxn but do you have any idea how can I attach cookie with this? my context is that i'm redirecting in successful registration with `res.redirect(307, "/admin");` However I tried res.cookie with cookieParser but none seems to works since I have fetch request and it's not storing cookie or someting? –  May 01 '23 at 16:03
6

Keep in mind the middleware architecture: Each handler may manipulate the context, and either respond - or - call next().

By this premise, the express router is basically a middleware function you may use after "correcting" the url.

(BTW, the request app is also a function, although I'm not sure if I recommend going back so early in the chain)

Here's a kind'a example:

const router = new require('express').Router()
const user = require('../model/user') 
//assume user implements:
//  user.byId(id) -> Promise<user>
//  user.byMail(email) -> Promise<user>

const reqUser = userPromise => (req, res, next) =>
   req.user
     ? next()
     : userPromise(req)
       .then(user => { req.user = user })
       .then(next, next)
//assume the sever that uses this router has a 
//standard (err, req, res, next) handler in the end of the chain...

const byId = reqUser( req => user.byId(req.params.id) )
const byMail = reqUser( req => user.byMail(req.params.mail) )

router.post('/by-id/:id/friends',
  byId,
  (req, res) => res.render('user-friends', req.user)
)

router.post('/by-email/:email/friends',
  byMail,
  (req, res, next) => {
     req.url = `/by-id/${req.user.id}/friends`
     next()
  }, 
  router
)
Radagast the Brown
  • 3,156
  • 3
  • 27
  • 40
5

The only difference between 307 and 302 is that 307 guarantees that the method and the body will not be changed when the redirected request is made.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307

pshx
  • 897
  • 1
  • 8
  • 9
4

I believe the question is that the node server is receiving a POST request but needs to redirect it to a different server as GET request. I recently had to deal with something similar. Here is how I solved it:

var proxy = require('express-http-proxy');

app.use('incomin/url', proxy('forwarding:server', {
    //The proxyRqDecorator allows us to change a few things including the request type.

proxyReqOptDecorator: (proxyReqOpts, srcReq) => {
    proxyReqOpts.method = 'GET';
    return proxyReqOpts;
},

//The proxyReqPathResolver takes the Given URL and updates it to the forward path
proxyReqPathResolver: function (req) {
    return new Promise( (resolve, reject) => {
        setTimeout( () =>{
            var value = req.body.key;
            var resolvedPathValue = 'forwarding/url' + value;
            console.log(`Inside forward path. The resolved path is ${resolvedPathValue}`);
            resolve(resolvedPathValue);
        }, 200);
    });
}
}));

Keep in mind that the above proxyReqPathResolver is setup async. The synchronous vesrion and more info on express-http-proxy are described here: https://www.npmjs.com/package/express-http-proxy

0

These days I'ld also consider a redirect with the code 308, e.g. with express

app.post('/', (req, res) => res.redirect(308, '/graphql'));

According to the documentation, 308 preserves not only the HTTP method, but also indicates this is a permanent redirect.

NotX
  • 1,516
  • 1
  • 14
  • 28