Why POST redirects to GET and PUT redirects to PUT

2019-01-24 09:35发布

问题:

I am using express 4.13.3 (latest) and following code:

var express = require('express')

var app = express()

app.get('/test', function (req, res, next) {
  res.send('hello!')
})

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

app.put('/test', function (req, res, next) {
  res.redirect('/test')
})

app.listen(5001)

// GET /test -> 'hello!'
// POST /test -> 'hello!'
// PUT /test -> ERR_TOO_MANY_REDIRECTS

POST redirects to GET but PUT redirects to PUT. Is it possible to make PUT redirect to GET (same as POST)?

回答1:

Before diving in the details, below is one way of how you could solve the problem:

app.put('/test', function(req, res, next) {
    res.redirect(303, '/test') // Notice the 303 parameter
})

By default Express uses HTTP code 302 for the redirect. According to the HTTP specification, this prevents POST/PUT requests from being redirected as POST/PUT requests and explains what you observed in your code:

If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

On the other hand, if you use a 303 redirect, the POST/PUT request is allowed to be redirected as a POST/PUT request as explained in this great SO answer:

303: Redirect for undefined reason. Typically, 'Operation has completed, continue elsewhere.' Clients making subsequent requests for this resource should not use the new URI. Clients should follow the redirect for POST/PUT/DELETE requests.



回答2:

First, let's understand what res.redirect does:

res.redirect([status,] path)

Redirects to the URL derived from the specified path, with specified HTTP status code status. If you don’t specify status, the status code defaults to “302 “Found”.

If we look at the HTTP 1.1 spec for a 302 response, we see

Note: For historical reasons, a user agent MAY change the request method from POST to GET for the subsequent request. If this behavior is undesired, the 307 (Temporary Redirect) status code can be used instead.

A 307 request will preserve the HTTP verb in all cases, but that's not want you want. You want the verb to change to GET. In that case, you want a 303:

303 See Other

The 303 (See Other) status code indicates that the server is redirecting the user agent to a different resource, as indicated by a URI in the Location header field, which is intended to provide an indirect response to the original request. A user agent can perform a retrieval request targeting that URI (a GET or HEAD request if using HTTP), which might also be redirected, and present the eventual result as an answer to the original request.

A 303 response will prompt the client (provided it understands HTTP 1.1) to perform a GET request on the specified resource. So, simply provide a 303 status code in your redirects:

res.redirect(303, '/test')


回答3:

The way of put is correct, you are redirecting request to another location, but the http method is same. And thats why it is trying to access put again.(You are not changing http method.)

Why post is redirecting to get

Here is answer.