¿Por qué HTTP no tiene redirección POST?

162

Las redirecciones HTTP se realizan a través de los códigos HTTP 301 y 302 (quizás también otros códigos) y un campo de encabezado conocido como "Ubicación" que tiene la dirección del nuevo lugar al que ir. Sin embargo, los navegadores siempre envían una solicitud "GET" a esa URL.

Sin embargo, muchas veces necesita redirigir a su usuario a otro dominio a través de POST (pagos bancarios, por ejemplo). Este es un escenario común y realmente un requisito. ¿Alguien sabe por qué un requisito tan común se ha descuidado en la especificación HTTP? La solución consiste en enviar un formulario (con parámetros en campos ocultos) con la acción establecida en la ubicación de destino (el valor del campo de encabezado Ubicación ) y utilizar setTimeoutpara enviar el formulario a la ubicación de destino.

Saeed Neamati
fuente
1
¿Es el código de estado 307 lo que estás buscando? Vea mi respuesta a continuación.
David Ruttka

Respuestas:

180

En HTTP 1.1, en realidad hay un código de estado ( 307 ) que indica que la solicitud debe repetirse utilizando el mismo método y publicar datos .

Como han dicho otros, existe la posibilidad de un mal uso aquí, por lo que muchos marcos se adhieren a 301 y 302 en sus abstracciones. Sin embargo, con la comprensión adecuada y el uso responsable, debería poder lograr lo que está buscando.

Tenga en cuenta que de acuerdo con la especificación W3.org , cuando METHODno es HEADo GET, los agentes de usuario deben avisar al usuario antes de volver a ejecutar la solicitud en la nueva ubicación. También debe proporcionar una nota y un mecanismo alternativo para el usuario en caso de que los agentes de usuario antiguos no estén seguros de qué hacer con un 307.

Usando este formulario:

<form action="Test307.aspx" method="post">
    <input type="hidden" name="test" value="the test" />
    <input type="submit" value="test" />    
</form>

Y tener Test307.aspx simplemente devuelve 307 con la ubicación: http://google.com , Chrome 13 y Fiddler confirman que "test = the test" está publicado en Google. Por supuesto, la respuesta adicional es un 405 ya que Google no permite la POST, pero muestra la mecánica.

Para obtener más información, consulte la Lista de códigos de estado HTTP y la especificación W3.org .

307 Redirección temporal (desde HTTP / 1.1) En esta ocasión, la solicitud debe repetirse con otro URI, pero las solicitudes futuras aún pueden usar el URI original. 2 A diferencia de 303, el método de solicitud no debe cambiarse al volver a emitir la solicitud original. Por ejemplo, una solicitud POST debe repetirse utilizando otra solicitud POST.

David Ruttka
fuente
2
@DavidRuttka, ¿Cuál es el soporte del navegador en la naturaleza ?
Pacerier
55
@DavidRuttka es posible que desee actualizar su respuesta para tener en cuenta rfc7231 (obsoletos rfc2616). Solicitar al usuario se basa en un requisito de rfc2616. Este requisito se elimina en rfc7231 y rfc7231 también introduce el requisito de que las redirecciones 307 no deben cambiar el método de solicitud (que usted menciona en su presupuesto al final de su respuesta).
nibarius
Tenga en cuenta que de acuerdo con tools.ietf.org/id/draft-hunt-http-rest-redirect-00.html "Los códigos de redirección HTTP 301-306 NO DEBEN utilizarse a menos que el proveedor del servicio sepa que el cliente es en realidad un usuario- agente "Parece que los servicios ReSTful deberían usar 308 en lugar de 301. Sin embargo, esto es solo un borrador.
Bruce Adams
49

Encontré una buena explicación en esta página aquí .

Las situaciones más simples en la WWW son las transacciones "idempotentes", es decir, aquellas que pueden repetirse sin causar ningún daño. Estas son típicamente transacciones "GET", ya sea porque son la recuperación de referencias directas de URL (por ejemplo, href = o src = atributos en HTML), o porque son envíos de formularios utilizando el método GET. Redirigir una transacción de ese tipo es sencillo y no se hacen preguntas: el cliente recibe la respuesta de redireccionamiento, que incluye un encabezado Ubicación: que especifica la nueva URL, y el cliente reacciona a ella volviendo a emitir la transacción a la nueva URL. Hay una diferencia entre los diferentes códigos de estado 30x asociados con estas redirecciones en su capacidad de almacenamiento en caché implícita, pero por lo demás son básicamente similares (301 y 302) en respuesta a las solicitudes GET.

Las transacciones POST son diferentes, ya que se definen como, en principio, no idempotentes (como pedir una pizza, emitir un voto o lo que sea) y no deben repetirse arbitrariamente.

Las especificaciones del protocolo HTTP están diseñadas para tener en cuenta esta distinción: el método GET se define como inherentemente idempotente, mientras que el método POST se define como, al menos potencialmente, no idempotente; Las especificaciones requieren una serie de precauciones que deben tomar los agentes del cliente (como los navegadores) para proteger a los usuarios contra (re) enviar inadvertidamente una transacción POST que no pretendían, o enviar una POST en un contexto que no hubieran deseado .

Si bien no soy fanático de restringir técnicamente a los usuarios para evitar que causen un caos no deseado o que causen daños no deseados a sus aplicaciones, puedo entender el punto y tiene sentido.

Halcón
fuente
Gran parte del razonamiento se refiere a los días en que los intertubos eran lentos y poco confiables (que todavía se encuentran en muchos lugares del mundo). Recuerdo claramente cuando usaba el acceso telefónico y me desconectaba aleatoriamente cuando alguien más levantaba el teléfono. Era mejor volver a cargar la página y ver en qué estado estaba el servidor que volver a enviar cosas y correr el riesgo de realizar la misma acción dos veces.
zzzzBov
@Falcon, ¿aumentar el "contador de visitantes" se consideraría no idempotente? Si es así, casi ningún sitio web en estos días tiene GET idempotentes ...
Pacerier
@Pacerier: Por lo general, idempotente se interpreta como "idempotente de manera significativa", por ejemplo, comprar el mismo artículo dos veces, no marcar dos visitas. De lo contrario, estarías en lo cierto. Pero en realidad, la especificación debería haber requerido que los servidores fueran significativamente idempotentes cuando fuera necesario, como incrustar una ID en la página para evitar duplicaciones, sin requerir que el navegador le haga al usuario una pregunta que no tiene forma de responder con precisión. En cualquier caso, la prevención de una redirección de un POST no afecta la idempotencia; es simplemente un mensaje que dice que el objetivo de la solicitud está realmente allí.
Lawrence Dol
No veo cómo esto tiene sentido para este razonamiento. Digamos que estoy en el sitio web del banco Chase y presento un formulario. Ya estuve de acuerdo / confié en ellos. Entonces, si tienen que redirigir esos datos a otra página, ¿por qué tendría que estar de acuerdo otra vez? O otro ejemplo, digamos que soy una persona que desactiva JavaScript de forma predeterminada. Un día voy a completar una aplicación de hipoteca en línea y cuando envío el formulario tiene errores. Sería genial si la aplicación puede redirigir (con POST) a la página que acabo de completar para rellenar previamente los datos.
b01
@Flacon, necesito pruebas de que restringir una redirección con POST puede evitar el caos en cualquier aspecto. Como primero tengo que confiar en la aplicación con mis datos, pueden hacer lo que quieran con ellos una vez que tengan los datos. Y no creo que las redirecciones sean más vulnerables que las solicitudes con POST.
b01
3

GET (y algunos otros métodos) se definen como 'SEGURO' en la especificación http ( RFC 2616 ):

9.1.1 Métodos seguros

Los implementadores deben ser conscientes de que el software representa al usuario en sus interacciones a través de Internet, y deben tener cuidado para permitir que el usuario sea consciente de cualquier acción que pueda tomar que pueda tener un significado inesperado para ellos u otros.

En particular, se ha establecido que los métodos GET y HEAD NO DEBEN tener la importancia de tomar una acción que no sea la recuperación. Estos métodos deben considerarse "seguros". Esto permite a los agentes de usuario representar otros métodos, como POST, PUT y DELETE, de una manera especial, de modo que el usuario sea consciente del hecho de que se está solicitando una acción posiblemente insegura.

Naturalmente, no es posible garantizar que el servidor no genere efectos secundarios como resultado de realizar una solicitud GET; de hecho, algunos recursos dinámicos lo consideran una característica. La distinción importante aquí es que el usuario no solicitó los efectos secundarios, por lo que no se le puede hacer responsable de ellos.

Esto significa que una solicitud GET nunca debería tener una consecuencia grave para el usuario, más allá de ver algo que tal vez no quiera ver, pero una solicitud POST podría cambiar un recurso que es importante para ellos o para otras personas.

Aunque esto ha cambiado con JavaScript, tradicionalmente había diferentes interfaces de usuario: los usuarios podían activar solicitudes GET haciendo clic en los enlaces, pero tendrían que completar un formulario para activar una solicitud POST. Creo que los diseñadores de HTTP estaban interesados ​​en mantener la distinción entre métodos seguros y no seguros.

Tampoco creo que deba ser necesario redirigir a una POST. Presumiblemente, cualquier acción que deba llevarse a cabo se puede realizar llamando a una función dentro del código del lado del servidor, o si tiene que suceder en un servidor diferente, en lugar de enviar una redirección que contenga una URL para que el navegador la envíe al servidor. podría hacer una solicitud a ese servidor en sí mismo, actuando como un proxy para el usuario.

bdsl
fuente