¿Cómo se envían los parámetros en una solicitud HTTP POST?

1476

En una solicitud HTTP GET , los parámetros se envían como una cadena de consulta :

http://example.com/page ? parameter = value & also = another

En una solicitud HTTP POST , los parámetros no se envían junto con el URI.

¿Dónde están los valores? En el encabezado de la solicitud? En el cuerpo de la solicitud? Cómo se ve?

Camilo Martin
fuente

Respuestas:

1254

Los valores se envían en el cuerpo de la solicitud, en el formato que especifica el tipo de contenido.

Por lo general, el tipo de contenido es application/x-www-form-urlencoded, por lo que el cuerpo de la solicitud usa el mismo formato que la cadena de consulta:

parameter=value&also=another

Cuando usa una carga de archivo en el formulario, usa la multipart/form-datacodificación, que tiene un formato diferente. Es más complicado, pero generalmente no es necesario que te importe cómo se ve, así que no mostraré un ejemplo, pero puede ser bueno saber que existe.

Guffa
fuente
25
Olvidé que las cargas de archivos son diferentes (+ 1 / aceptado). Su respuesta es suficiente, aunque sería más agradable si tuviera más información multipart/form-data. Sin embargo, para aquellos interesados, aquí hay una pregunta al respecto .
Camilo Martin
73
NOTA : el cuerpo está separado del encabezado por una sola línea en blanco .
Gab 是 好人
2
Usted explicó lo que colocamos en HTTPBody, pero ¿qué colocamos / escribimos en HTTPHeader? ¿Para qué sirve?
Miel
44
@Honey: El encabezado HTTP para una publicación se parece a uno para obtener, pero con el verbo POST en lugar de GET, y un valor de tipo de contenido (y un valor de longitud de contenido opcional) ya que la solicitud tiene contenido (cuerpo). Cada tipo de solicitud tiene un encabezado, algunos tipos también tienen un cuerpo.
Guffa
44
@KennethWorden No, ninguno de los métodos enviará correctamente JSON. sin embargo, puede cargar un archivo json en un formulario codificado con multipart/form-datao si está a cargo de la construcción de la solicitud, cambiar el tipo de contenido application/jsony pegar el texto json en el cuerpo http directamente
Cholthi Paul Ttiopic
428

El contenido se coloca después de los encabezados HTTP. El formato de una POST HTTP es tener los encabezados HTTP, seguidos de una línea en blanco, seguida del cuerpo de la solicitud. Las variables POST se almacenan como pares clave-valor en el cuerpo.

Puede ver esto en el contenido sin formato de una publicación HTTP, que se muestra a continuación:

POST /path/script.cgi HTTP/1.0
From: [email protected]
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Puede ver esto usando una herramienta como Fiddler , que puede usar para ver la carga de solicitud y respuesta HTTP sin procesar que se envía a través del cable.

Joe Alfano
fuente
39
Solo si el tipo de contenido es application/x-www-form-urlencoded, que no siempre es el caso.
Guffa
@ Camilo Martin ... [+1] por una gran pregunta y @ Joe Alfano ... [+1] por una gran respuesta ... Ahora tengo una idea clara sobre la solicitud POST ... pero si una imagen viene junto con información clave, valor par de datos ..... ¿Cómo se ve la estructura de POST?
Devrath el
99
@ Joe, ahora ¿por qué tendrías un Fromencabezado allí?
Pacerier
@ Joe, me encanta la inclusión aleatoria del Fromencabezado. OMI está ahí arriba con el código de estado 418 HTTP.
Tom Howard
¿Cómo se agrega una autenticación de usuario y contraseña?
m4l490n
376

Respuesta corta: en las solicitudes POST, los valores se envían en el "cuerpo" de la solicitud. Con los formularios web, lo más probable es que se envíen con un tipo de medio de application/x-www-form-urlencodedo multipart/form-data. Los lenguajes de programación o marcos que han sido diseñados para manejar las peticiones web por lo general hacer "la cosa correcta ™" con tales peticiones y le proporcionará un acceso fácil a los valores decodificados fácilmente (como $_REQUESTo $_POSTen PHP, o cgi.FieldStorage(), flask.request.formen Python).


Ahora pasemos un poco, lo que puede ayudar a entender la diferencia;)

La diferencia entre GETy las POSTsolicitudes son en gran medida semánticas. También se "usan" de manera diferente, lo que explica la diferencia en cómo se pasan los valores.

GET ( sección RFC relevante )

Al ejecutar una GETsolicitud, le pide al servidor una o un conjunto de entidades. Para permitir que el cliente filtre el resultado, puede usar la llamada "cadena de consulta" de la URL. La cadena de consulta es la parte después de ?. Esto es parte de la sintaxis de URI .

Por lo tanto, desde el punto de vista del código de su aplicación (la parte que recibe la solicitud), deberá inspeccionar la parte de consulta URI para obtener acceso a estos valores.

Tenga en cuenta que las claves y los valores son parte del URI. Los navegadores pueden imponer un límite en la longitud de URI. El estándar HTTP establece que no hay límite. Pero en el momento de escribir estas líneas, la mayoría de los navegadores no limitan los URI (no tengo valores específicos). GETlas solicitudes nunca deben usarse para enviar nueva información al servidor. Especialmente no documentos más grandes. Ahí es donde debes usar POSTo PUT.

POST ( sección RFC relevante )

Al ejecutar una POSTsolicitud, el cliente está enviando un nuevo documento al host remoto. Por lo tanto, una cadena de consulta no tiene sentido (semánticamente). Es por eso que no tiene acceso a ellos en su código de aplicación.

POSTes un poco más complejo (y mucho más flexible):

Al recibir una solicitud POST, siempre debe esperar una "carga útil" o, en términos HTTP: un cuerpo de mensaje . El cuerpo del mensaje en sí mismo es bastante inútil, ya que no hay un formato estándar (por lo que puedo decir. ¿Tal vez aplicación / octeto-flujo?). El formato del cuerpo está definido por el Content-Typeencabezado. Cuando se usa un FORMelemento HTML con method="POST", esto suele ser application/x-www-form-urlencoded. Otro tipo muy común es multipart / form-data si usa cargas de archivos. Pero podría ser cualquier cosa , desde text/plain, más application/jsono incluso una costumbre application/octet-stream.

En cualquier caso, si se realiza una POSTsolicitud con una Content-Typeque no puede ser manejada por la aplicación, debe devolver un 415código de estado .

La mayoría de los lenguajes de programación (y / o marcos web) ofrecen una forma de descodificar / codificar el cuerpo del mensaje de / a los tipos más comunes (como application/x-www-form-urlencoded, multipart/form-datao application/json). Entonces eso es fácil. Los tipos personalizados requieren potencialmente un poco más de trabajo.

Usando un documento codificado estándar de formulario HTML como ejemplo, la aplicación debe realizar los siguientes pasos:

  1. Lee el Content-Typecampo
  2. Si el valor no es uno de los tipos de medios admitidos, devuelva una respuesta con un 415código de estado
  3. de lo contrario, decodifique los valores del cuerpo del mensaje.

Una vez más, los lenguajes como PHP o los marcos web para otros lenguajes populares probablemente lo manejarán por usted. La excepción a esto es el 415error. Ningún marco puede predecir qué tipos de contenido elige admitir y / o no admitir su aplicación. Esto depende de ti.

PUT ( sección RFC relevante )

Una PUTsolicitud se maneja de la misma manera que una POSTsolicitud. La gran diferencia es que POSTse supone que una solicitud permite que el servidor decida cómo (y si es que lo hace) crear un nuevo recurso. Históricamente (a partir del ahora obsoleto RFC2616 fue crear un nuevo recurso como "subordinado" (hijo) del URI al que se envió la solicitud).

En PUTcambio, se supone que una solicitud "deposita" un recurso exactamente en ese URI y con exactamente ese contenido. Ni mas ni menos. La idea es que el cliente sea ​​responsable de crear el recurso completo antes de "PONERLO". El servidor debe aceptar que tal y como está en la URL dada.

Como consecuencia, una POSTsolicitud generalmente no se usa para reemplazar un recurso existente. Una PUTsolicitud puede crear y reemplazar.

Nota al margen

También hay " parámetros de ruta " que se pueden usar para enviar datos adicionales al control remoto, pero son tan poco comunes que no voy a entrar en demasiados detalles aquí. Pero, como referencia, aquí hay un extracto del RFC:

Además de los segmentos de puntos en las rutas jerárquicas, la sintaxis genérica considera que un segmento de ruta es opaco. Las aplicaciones que producen URI a menudo usan los caracteres reservados permitidos en un segmento para delimitar subcomponentes específicos del esquema o del controlador de referencia. Por ejemplo, los caracteres reservados con punto y coma (";") e igual ("=") a menudo se usan para delimitar parámetros y valores de parámetros aplicables a ese segmento. El carácter reservado con coma (",") se utiliza a menudo para fines similares. Por ejemplo, un productor de URI podría usar un segmento como "nombre; v = 1.1" para indicar una referencia a la versión 1.1 de "nombre", mientras que otro podría usar un segmento como "nombre, 1.1" para indicar lo mismo. Los tipos de parámetros pueden definirse por una semántica específica del esquema,

exhuma
fuente
1
Puede que haya hecho una ligera tangente. Agregué un "tl; dr" a la parte superior de la respuesta que debería aclararlo.
exhuma el
También lo edité para hacer referencia a RFC7231 en lugar de RFC2616 (que ha estado obsoleto por un tiempo). La principal diferencia para esta respuesta, aparte de los enlaces actualizados, se encuentra en la sección "PUT".
exhuma el
Pensé que PUT se manejó de manera diferente a POST ya que se supone que es idempotente. stackoverflow.com/questions/611906/…
rogerdpack
1
@rogerdpack No te equivocas. Si lees el segundo párrafo de la PUTsección, verás que es idempotente. POSTen contraste puede, por definición, no ser. POSTsiempre creará un nuevo recurso. PUTserá, si existe un recurso idéntico reemplazarlo. Entonces, si llamas POST10 veces, crearás 10 recursos. Si llama PUT10 veces, (quizás) creará solo una. Eso responde tu pregunta?
exhuma
60

No puede escribirlo directamente en la barra de URL del navegador.

Puede ver cómo se envían los datos POST en Internet con Live HTTP Headers, por ejemplo. El resultado será algo así

http://127.0.0.1/pass.php
POST /pass.php HTTP/1.1

Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/pass.php
Cookie: passx=87e8af376bc9d9bfec2c7c0193e6af70; PHPSESSID=l9hk7mfh0ppqecg8gialak6gt5
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=zurfyx&pass=password

En donde dice

Content-Length: 30
    username=zurfyx&pass=password

serán los valores publicados.

zurfyx
fuente
2
Aclaración: se Content-Lengthsupone que debe estar 29aquí? Esa es la longitud real de la cuerda username=zurfyx&pass=password.
Hippo
@Hippo era un personaje de nueva línea destinado a estar allí?
vikingsteve
@vikingsteve Ya veo lo que quieres decir. Entonces, supongo que el Contenido siempre tiene una nueva línea al final.
Hippo
2
El encabezado se separa del cuerpo con nueva línea adicional
Mára Toner
24

El tipo de medio predeterminado en una solicitud POST es application/x-www-form-urlencoded. Este es un formato para codificar pares clave-valor. Las claves pueden ser duplicadas. Cada par clave-valor está separado por un &carácter, y cada clave está separada de su valor por un =carácter.

Por ejemplo:

Name: John Smith
Grade: 19

Está codificado como:

Name=John+Smith&Grade=19

Esto se coloca en el cuerpo de la solicitud después de los encabezados HTTP.

Nejat
fuente
1
Usted explicó lo que colocamos en HTTPBody, pero ¿qué colocamos / escribimos en HTTPHeader?
Miel
Usted mencionó que la clave puede ser duplicada, entonces, ¿cuál es el resultado de tal duplicado? ¿El último sobrescribirá automáticamente los valores anteriores? Gracias.
Jinghui Niu
@JinghuiNiu si la clave está duplicada, debe analizarse como una matriz. Esto es muy tarde pero podría ayudar a alguien más.
Hanash Yaslem
18

Los valores de formulario en HTTP POST se envían en el cuerpo de la solicitud, en el mismo formato que la cadena de consulta.

Para más información, consulte las especificaciones .

SLaks
fuente
55
El "mismo formato" es un poco ambiguo. ¿Comienzan con un ?por ejemplo?
Camilo Martin
77
@PeterWooster Sí, pero no proporciona un ejemplo. En ese sentido, es como una respuesta que dice "mira, hay una respuesta para tu pregunta en el blog de la aplicación (enlace) ".
Camilo Martin el
36
@PeterWooster No es necesario, pero es muy bueno cuando olvidas algo, busca en Google, ve al primer enlace que es SO, y hay un ejemplo claro y conciso que te dice lo que necesitas en lugar de enviarte a masticar especificaciones excesivamente detalladas que, incluso si son completas, pueden no ser aptas para actualizaciones. Piénselo: la mayoría de los QA en este sitio podrían reducirse a "ir a leer las especificaciones / manual / API / etc (enlace) ". ¿Sería útil? No más que Google.
Camilo Martin el
2
Solo si el tipo de contenido es application/x-www-form-urlencoded, que no siempre es el caso.
Guffa
3
El formato de la cadena de consulta GET es diferente del de application / x-www-form-urlencoded. Por ejemplo, el espacio en blanco se codifica de manera diferente (% 20 vs +). La respuesta es engañosa a este respecto.
UnclickableCharacter
18

Algunos de los servicios web requieren que coloque los datos y metadatos de la solicitud por separado. Por ejemplo, una función remota puede esperar que la cadena de metadatos firmada se incluya en un URI, mientras que los datos se publican en un cuerpo HTTP.

La solicitud POST puede verse semánticamente así:

POST /?AuthId=YOURKEY&Action=WebServiceAction&Signature=rcLXfkPldrYm04 HTTP/1.1
Content-Type: text/tab-separated-values; charset=iso-8859-1
Content-Length: []
Host: webservices.domain.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

name    id
John    G12N
Sarah   J87M
Bob     N33Y

Este enfoque combina lógicamente QueryString y Body-Post utilizando un único Content-Typeque es una "instrucción de análisis" para un servidor web.

Tenga en cuenta: HTTP / 1.1 está envuelto con el #32(espacio) a la izquierda y con #10(Avance de línea) a la derecha.

Interfaz desconocida
fuente
La diferencia entre /user/johny /?user=johnes meramente semántica (HTTP realmente no da un tratamiento especial a las cadenas de consulta), por lo que considero que esto es razonablemente esperado. Pero, ¿qué quieres decir con "envuelto por el espacio a la izquierda"? No hay espacios antes del método HTTP. ¿Te refieres a la línea en blanco para el cuerpo de la publicación?
Camilo Martin
Hay un espacio (ASCII # 32) entre ...Ym04y HTTP/1.1en el código anterior. Entonces, un QueryString simplemente reside entre el verbo y la versión del protocolo.
Interfaz desconocida el
1
Su nota hace que parezca algo inesperado y específico de la versión. Francamente, parece obvio que hay un espacio allí. Y el avance de línea también se aplica a las otras líneas, como todas las cosas unix.
Camilo Martin
1
Solo enfaticé lo que no podía marcar en el código. Puede parecer obvio, pero a veces no lo es.
Interfaz desconocida el
Es cierto que podríamos pasar los parámetros de consulta como parte de la URL separando el URI y los parámetros de la ?misma manera que lo hacemos con las GETsolicitudes.
pregunta el
8

En primer lugar, diferenciemos entre GETyPOST

Obtener: es la HTTPsolicitud predeterminada que se realiza al servidor y se utiliza para recuperar los datos del servidor y la cadena de consulta que viene después ?de a URIse utiliza para recuperar un recurso único.

este es el formato

GET /someweb.asp?data=value HTTP/1.0

Aquí data=valueestá el valor de cadena de consulta pasado.

POST: se utiliza para enviar datos al servidor de forma segura, por lo que cualquier cosa que se necesite, este es el formato de una POSTsolicitud

POST /somweb.aspHTTP/1.0
Host: localhost
Content-Type: application/x-www-form-urlencoded //you can put any format here
Content-Length: 11 //it depends
Name= somename

¿Por qué publicar en GET?

En GETel valor que se envía a los servidores generalmente se agrega a la URL base en la cadena de consulta, ahora hay 2 consecuencias de esto

  • Las GETsolicitudes se guardan en el historial del navegador con los parámetros. Por lo tanto, sus contraseñas permanecen sin cifrar en el historial del navegador. Este era un problema real para Facebook en aquellos días.
  • Por lo general, los servidores tienen un límite sobre cuánto tiempo URIpuede durar. Si se envían demasiados parámetros, es posible que reciba414 Error - URI too long

En caso de una solicitud posterior, sus datos de los campos se agregan al cuerpo. La longitud de los parámetros de solicitud se calcula y se agrega al encabezado para la longitud del contenido y no se agregan datos importantes directamente a la URL.

Puede utilizar la sección de red de Herramientas para desarrolladores de Google para ver información básica sobre cómo se realizan las solicitudes a los servidores.

y siempre se puede añadir más valores en el Request Headerscomo Cache-Control, Origin, Accept.

Zeeshan Adil
fuente
44
Las suposiciones sobre seguridad solo son ciertas en el contexto de una HTTPSconexión, no HTTP. HTTPScifra tanto el URL(incluidos los parámetros de consulta) como el Request Body, cuando no HTTPcifra ni protege ninguno. El problema descrito proviene del hecho de que muchos navegadores almacenan el URIs(incluido URLs) en sus bases de datos de historial (generalmente no encriptado). Por lo tanto, use solo el Request Body+ HTTPSpara cualquier cosa sensible.
Petru Zaharia
@PetruZaharia Estoy de acuerdo con tu explicación. ¡También puedes sugerir esto como edición y estaré encantado de aceptar! :)
Zeeshan Adil