如何在HTTP POST请求中发送参数?

在HTTPget请求中,参数作为查询字符串发送:

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

In an HTTP POST request, the parameters are not sent along with the URI.

Where are the values? In the request header? In the request body? What does it look like?

2596148 次浏览

HTTP POST中的表单值以与查询字符串相同的格式在请求正文中发送。

有关详细信息,请参阅规格

内容放在HTTP标头之后。HTTP POST的格式是包含HTTP标头,后跟空行,后跟请求正文。POST变量在正文中以键值对的形式存储。

您可以在HTTP Post的原始内容中看到这一点,如下所示:

POST /path/script.cgi HTTP/1.0From: frog@jmarshall.comUser-Agent: HTTPTool/1.0Content-Type: application/x-www-form-urlencodedContent-Length: 32
home=Cosby&favorite+flavor=flies

您可以使用小提琴手之类的工具看到这一点,您可以使用它来查看通过网络发送的原始HTTP请求和响应有效负载。

您不能直接在浏览器URL栏上键入它。

例如,您可以看到POST数据是如何在Internet上以实时HTTP标头发送的。结果会是这样的

http://127.0.0.1/pass.phpPOST /pass.php HTTP/1.1
Host: 127.0.0.1User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateDNT: 1Referer: http://127.0.0.1/pass.phpCookie: passx=87e8af376bc9d9bfec2c7c0193e6af70; PHPSESSID=l9hk7mfh0ppqecg8gialak6gt5Connection: keep-aliveContent-Type: application/x-www-form-urlencodedContent-Length: 30username=zurfyx&pass=password

上面写着

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

将是后值。

这些值以内容类型指定的格式在请求正文中发送。

通常内容类型为application/x-www-form-urlencoded,因此请求正文使用与查询字符串相同的格式:

parameter=value&also=another

当你在表单中使用文件上传时,你使用multipart/form-data编码,它有不同的格式。它更复杂,但你通常不需要关心它是什么样子,所以我不会展示一个例子,但知道它存在会很好。

POST请求中的默认媒体类型是application/x-www-form-urlencoded。这是一种编码键值对的格式。键可以是重复的。每个键值对由&字符分隔,每个键与其值由=字符分隔。

例如:

Name: John SmithGrade: 19

编码为:

Name=John+Smith&Grade=19

它被放置在HTTP标头之后的请求正文中。

简短的回答:在POST请求中,值在请求的“主体”中发送。对于Web表单,它们很可能以application/x-www-form-urlencodedmultipart/form-data的媒体类型发送。旨在处理Web请求的编程语言或框架通常会对此类请求进行“正确的事情™”,并为您提供轻松访问容易解码的值(例如PHP中的$_REQUEST$_POST,或Python中的cgi.FieldStorage()flask.request.form)。


现在让我们离题一点,这可能有助于理解差异;)

GETPOST请求之间的差异主要是语义上的。它们的“使用”也不同,这解释了值传递方式的差异。

GET(相关rfc部分

执行GET请求时,您向服务器请求一个或一组实体。为了允许客户端过滤结果,它可以使用URL的所谓“查询字符串”。查询字符串是?之后的部分。这是URI语法的一部分。

因此,从应用程序代码(请求接收的部分)的角度来看,您需要检查URI查询部分以访问这些值。

请注意,键和值是URI的一部分。浏览器可能对URI长度施加了限制。HTTP标准规定没有限制。但在撰写本文时,大多数浏览器限制了URI(我没有特定的值)。GET请求应该从未用于向服务器提交新信息。尤其是较大的文档。这就是你应该使用POSTPUT的地方。

POST(相关rfc部分

当执行POST请求时,客户端实际上是在向远程主机提交一个新的文档。因此,查询字符串(语义上)没有意义。这就是为什么您无法在应用程序代码中访问它们。

POST有点复杂(方式更灵活):

当收到POST请求时,你应该总是期待一个“有效负载”,或者用HTTP术语来说:一个消息正文。消息主体本身非常无用,因为没有标准(据我所知。也许是应用程序/八位字节流?)格式。主体格式由Content-Type标头定义。当使用method="POST"的超文本标记语言FORM元素时,这通常是application/x-www-form-urlencoded。如果你使用文件上传,另一种非常常见的类型是多部分/表单数据。但它可能是FORM0,范围从text/plainapplication/json,甚至是自定义的application/octet-stream

在任何情况下,如果使用应用程序无法处理的Content-Type发出POST请求,它应该返回#2状态码

大多数编程语言(和/或Web框架)都提供了一种将消息主体从/编码为最常见类型(如application/x-www-form-urlencodedmultipart/form-dataapplication/json)的方法。所以这很容易。自定义类型可能需要更多的工作。

以标准超文本标记语言编码的文档为例,应用程序应执行以下步骤:

  1. 读取Content-Type字段
  2. 如果该值不是受支持的媒体类型之一,则返回带有415状态代码的响应
  3. 否则,解码消息正文中的值。

同样,PHP或其他流行语言的Web框架等语言可能会为您处理此问题。例外是415错误。没有框架可以预测您的应用程序选择支持和/或不支持哪些内容类型。这取决于您。

PUT(相关rfc部分

PUT请求的处理方式与POST请求几乎完全相同。最大的区别是POST请求应该让服务器决定如何(以及是否)创建新资源。从历史上看(从现在过时的RFC2616开始,它是作为请求发送到的URI的“从属”(子)创建一个新资源)。

相比之下,PUT请求应该“存放”一个资源,正好是那个URI,完全那个内容。不多不少。这个想法是客户端负责在“放置”它之前制作完成资源。服务器应该在给定的URL上接受它现状

因此,POST请求通常不用于取代现有资源。PUT请求可以同时创建替换。

旁注

还有“路径参数”可用于将其他数据发送到远程,但它们非常罕见,我不会在这里详细介绍。但是,作为参考,这里是RFC的摘录:

除了分层路径中的点段之外,还考虑路径段通用语法不透明。URI生成应用程序通常使用段中允许的保留字符来分隔特定于方案的或取消引用处理程序特定的子组件。例如,分号(“;”)和equals("=")保留字符通常用于分隔参数和适用于该段的参数值。保留逗号(“,”)字符通常用于类似的目的。例如,一个URI生产者可能会使用诸如“name; v=1.1”之类的段来指示对版本的引用1.1的“名称”,而另一个可能使用诸如“名称,1.1”之类的段来表示相同。参数类型可以由特定于方案的定义语义学,但在大多数情况下,参数的语法是特定的来实现URI取消引用算法。

某些Web服务要求您分别放置请求数据元数据。例如,远程函数可能期望签名的元数据字符串包含在URI中,而数据发布在HTTP主体中。

POST请求在语义上可能如下所示:

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

这种方法在逻辑上结合了QueryString和Body-Post,使用单个Content-Type,这是Web服务器的“解析指令”。

请注意: HTTP/1.1是包裹,左边是包裹2(空格),右边是#10(换行符)。

首先,让我们区分GETPOST

获取:这是向服务器发出的默认HTTP请求,用于从服务器检索数据,URI?之后的查询字符串用于检索唯一资源。

这是格式

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

这里data=value是传递的查询字符串值。

帖子:它用于安全地将数据发送到服务器,因此需要任何东西,这是POST请求的格式

POST /somweb.aspHTTP/1.0Host: localhostContent-Type: application/x-www-form-urlencoded //you can put any format hereContent-Length: 11 //it dependsName= somename

为什么POST超过GET?

GET中,发送到服务器的值通常附加到查询字符串中的基本URL,现在有两个结果

  • GET请求与参数一起保存在浏览器历史记录中。因此,您的密码在浏览器历史记录中保持未加密。这对Facebook来说是一个真正的问题。
  • 通常服务器对URI的长度有限制。如果发送的参数太多,您可能会收到414 Error - URI too long

在发布请求的情况下,您来自字段的数据将被添加到主体中。计算请求参数的长度,并将其添加到内容长度的标头中,并且没有重要数据直接附加到URL。

您可以使用Google开发人员工具的网络部分查看有关如何向服务器发出请求的基本信息。

你总是可以在你的Request Headers中添加更多的值,比如Cache-ControlOriginAccept

有很多方法/格式的后参数

  • formdata
  • 原始数据
  • json
  • 编码数据
  • 文件
  • xml

它们由Header中的内容类型控制,这些内容类型表示为mime类型。

在万维网上的CGI编程中,作者说:

使用POST方法,服务器将数据作为输入流发送到程序……因为服务器将信息传递给这个程序作为输入流,它将环境变量CONTENT_LENGTH设置为以字节数(或字符数)表示的数据大小。我们可以使用从标准输入中读取这么多数据。