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


1475

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

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

在HTTP POST请求中,参数不会与URI一起发送。

价值在哪里?在请求标头中?在请求正文中?它是什么样子的?

Answers:


1252

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

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

parameter=value&also=another

当您使用表单中的文件上传功能时,将使用multipart/form-data编码格式,而编码格式则不同。它比较复杂,但是您通常不需要关心它的外观,因此我不会显示示例,但是知道它的存在可能会很好。


25
我忘记了文件上传是不同的(+ 1 /接受)。您的答案就足够了,如果有更多信息,它会更好multipart/form-data。对于那些感兴趣的人,这是一个问题
卡米洛·马丁

73
注意:主体与标题之间仅用一个空白行隔开。
加布是好人

2
您已经说明了我们在HTTPBody中放置的内容,但是我们在HTTPHeader中放置/写入了什么内容?它有什么作用?
亲爱的

4
@Honey:帖子的HTTP标头看起来像是要获取的标头,但是带有动词POST而不是GET,并且内容类型值(和可选的内容长度值)是请求的内容(正文)。每种类型的请求都有一个标头,某些类型也有一个主体。
Guffa

4
@KennethWorden不,所有方法都不能正确发送JSON。但是,您可以上传一个JSON文件与编码的形式multipart/form-data,或者如果你在充电要求建设,改变内容类型的很对application/json,并在HTTP主体直接粘贴JSON文本
Cholthi保罗Ttiopic

428

内容放在HTTP标头之后。HTTP POST的格式是具有HTTP标头,后跟空白行,然后是请求正文。POST变量作为键值对存储在主体中。

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

POST /path/script.cgi HTTP/1.0
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

您可以使用Fiddler之类的工具来查看此信息,该工具可用于观察通过网络发送的原始HTTP请求和响应有效负载。


39
仅当内容类型application/x-www-form-urlencoded为时,情况并非总是如此。
Guffa 2013年

@ Camilo Martin .... [+1]很好的问题&@ Joe Alfano .... [+1]很好的答案....我现在对POST请求有了一个清晰的主意....但是,如果图像带有键,数据信息的值-值对..... POST的结构如何?
Devrath

9
@Joe,现在为什么在From那里有标题?
Pacerier 2014年

@Joe,我喜欢From标题的随机包含。IMO,它带有418 HTTP状态代码。
汤姆·霍华德

如何添加用户和密码验证?
m4l490n

376

简短的答案:在POST请求中,值在请求的“正文”中发送。对于网络表单,最有可能以application/x-www-form-urlencoded或的媒体类型发送它们multipart/form-data。编程语言或已被设计用于处理网络请求通常做“正确的事情™”这样的请求,并为您提供轻松前往容易解码值(如框架$_REQUEST$_POSTPHP中,或者cgi.FieldStorage()flask.request.form在Python)。


现在让我们讨论一下,这可能有助于理解差异;)

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

GET(相关的RFC部分

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

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

请注意,键和值是URI的一部分。浏览器可能会对URI长度施加限制。HTTP标准规定没有限制。但是在撰写本文时,大多数浏览器的确会限制URI(我没有具体值)。GET请求不能用于向服务器提交新信息。特别是没有较大的文档。那是您应该使用POST或的地方PUT

POST(相关的RFC部分

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

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

收到POST请求时,您应该始终期望“有效载荷”,或者用HTTP术语表示:消息正文。消息主体本身是没有用的,因为没有标准的格式(据我所知。也许是application / octet-stream?)。正文格式由Content-Type标题定义。当与HTML FORM元素一起使用时method="POST",通常为application/x-www-form-urlencoded。如果使用文件上传,则另一种非常常见的类型是multipart / form-data。但这可能是任何东西,范围从text/plain,结束application/json甚至是习俗application/octet-stream

无论如何,如果使用POST发出的请求Content-Type都无法由应用程序处理,则它应返回415状态码

大多数编程语言(和/或网络框架)提供了一种方法来解/编码的邮件正文从/最常见的类型(如application/x-www-form-urlencodedmultipart/form-dataapplication/json)。这很容易。自定义类型可能需要更多的工作。

以标准HTML表单编码的文档为例,应用程序应执行以下步骤:

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

同样,PHP之类的语言或其他流行语言的网络框架可能会为您解决这个问题。例外是415错误。没有框架可以预测您的应用选择支持和/或不支持的内容类型。这取决于你。

PUT(相关的RFC部分

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

PUT相反请求应该恰好“存款”的资源该URI,并用确切该内容。不多不少。这个想法是,客户有责任在“放入”之前制作完整的资源。服务器应在给定URL上原样接受它。

结果,POST通常不使用请求来替换现有资源。一个PUT请求可以创建替换。

边注

还有一些“ 路径参数 ”可用于将其他数据发送到远程,但是它们很少见,因此在此不再赘述。但是,作为参考,以下是RFC的摘录:

除了分层路径中的点段外,通用语法还认为路径段是不透明的。产生URI的应用程序通常使用段中允许的保留字符来分隔特定于方案或特定于解除引用处理程序的子组件。例如,分号(“;”)和等号(“ =”)保留字符通常用于定界适用于该段的参数和参数值。逗号(“,”)保留字符通常用于类似目的。例如,一个URI生产者可能使用诸如“ name; v = 1.1”之类的段来表示对“ name”的1.1版的引用,而另一家URI生产者可能使用诸如“ name,1.1”之类的段来表示相同。参数类型可以通过特定于方案的语义来定义,


1
我可能确实有点切线了。我在答案的顶部添加了一个“ tl; dr”,这应该使其更加清晰。
2014年

我还刚刚对其进行了编辑,以引用RFC7231而不是RFC2616(已经过时了一段时间)。除了更新的链接之外,此答案的主要区别在于“ PUT”部分。
2014年

我以为PUT与POST的处理方式不同,因为它应该是幂等的?stackoverflow.com/questions/611906/...
rogerdpack

1
@rogerdpack你没看错。如果您阅读了本PUT节的第二段,您将看到它幂等的。POST相反,按照定义,可以不是。POST将始终创建新资源。PUT如果存在相同的资源,则将其替换。因此,如果调用POST10次​​,则将创建10个资源。如果您拨打PUT10次​​,它将(可能)仅创建一次。这是否回答你的问题?
exhuma

59

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

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

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

它说的地方

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

将是职位价值。


2
澄清:Content-Length应该在29这里吗?那是字符串的实际长度username=zurfyx&pass=password
河马

@河马是一个换行符,打算在那里吗?
vikingsteve

@vikingsteve我明白你的意思了。因此,我想内容的末尾总会有换行符。
河马

2
头从身体有额外的换行分隔
马拉色调剂

24

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

例如:

Name: John Smith
Grade: 19

编码为:

Name=John+Smith&Grade=19

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


1
您已经说明了我们在HTTPBody中放置的内容,但是我们在HTTPHeader中放置/写入了什么内容?
亲爱的

您提到密钥可以重复,那么重复的结果是什么?最后一个会自动覆盖以前的值吗?谢谢。

@JinghuiNiu如果密钥重复,则应将其解析为数组。这已经很晚了,但可能会对其他人有所帮助。
Hanash Yaslem

18

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

有关更多信息,请参见规范


5
“相同格式”有点含糊。他们?以例如开头吗?
卡米洛·马丁

7
@PeterWooster是的,但没有提供示例。在这方面,就像一个回答说:“看,应用程序的博客(链接)中有您的问题的答案”。
卡米洛·马丁

36
@PeterWooster不需要,但是当您忘记一些东西,用谷歌搜索,转到第一个链接是SO时,这非常好,并且有一个简洁明了的示例告诉您您需要什么,而不是让您咀嚼过于详细的规范,即使是全面的规范也可能不适合复习。想想看:该站点上的大多数QA都可以归结为“去阅读spec / manual / API / etc (链接) ”。有用吗?不超过Google。
卡米洛·马丁

2
仅当内容类型application/x-www-form-urlencoded为时,情况并非总是如此。
Guffa 2013年

3
GET查询字符串的格式与application / x-www-form-urlencoded的格式不同。例如,空白的编码方式不同(%20与+)。在这方面,答案是误导的。
UnclickableCharacter 2014年

18

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

POST请求在语义上可能看起来像这样:

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

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

请注意: HTTP / 1.1 包裹#32左边,并用(空间)#10右侧(行)。


/user/john和之间的区别/?user=john只是语义上的区别(HTTP并没有对查询字符串进行特殊处理),因此我认为这是合理的。但是,“用左边的空间包裹”是什么意思?HTTP方法前没有空格。您是说帖子正文的空白行吗?
卡米洛·马丁

上面的代码之间...Ym04和之间有一个空格(ASCII#32)HTTP/1.1。因此,QueryString仅位于动词和协议版本之间。
未知的接口,2015年

1
您的笔记听起来好像是出乎意料且特定于版本的。坦率地说,似乎那里确实有空间。换行符也适用于其他行,就像所有unix一样。
卡米洛·马丁

1
我只是强调了我在代码中无法标记的内容。它可能看起来很明显,但有时却不是。
未知的接口,2015年

的确,我们可以通过将URI和参数分开来传递查询参数作为URL的一部分,?就像处理GET请求一样。
asgs

8

首先,让我们区分GETPOST

获取:这是默认的HTTP请求时向服务器和用于检索从后而来的服务器和查询字符串数据?中一个URI用于检索的独特资源。

这是格式

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

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

POST:用于安全地将数据发送到服务器,因此需要任何内容​​,这是POST请求的格式

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

为什么在GET之上发布?

GET发送到服务器的值中,通常将它们附加到查询字符串中的基本URL上,现在有2种结果

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

如果发布请求,则将字段中的数据添加到正文中。计算请求参数的长度,并将其添加到content-length的标头中,并且没有重要数据直接附加到URL。

您可以使用Google Developer Tools的网络部分来查看有关如何向服务器发出请求的基本信息。

你可以随时在你添加更多的价值Request Headers一样Cache-ControlOriginAccept


4
关于安全性的假设仅在HTTPS连接的情况下才成立,而在的情况下才成立HTTPHTTPS加密两者URL(包括查询参数)和Request Body,当HTTP加密/既不保护。所描述的问题来自许多浏览器将URIs(包括URLs)存储在其历史数据库中(通常未加密)的事实。因此,仅对敏感内容使用Request Body+ HTTPS
佩特鲁·扎哈里亚

@PetruZaharia我同意你的解释。您也可以建议将此作为编辑内容,我很乐意接受!:)
Zeeshan Adil
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.