ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

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

“在 HTTP POST 请求中,参数不与 URI 一起发送。” - 虽然它可以(只是理论上),但不要混淆其他人。根据规范,POST 必须服务于非幂等请求,但您可以使用请求主体(通过一个空行与标头分隔)以及请求参数。

G
Guffa

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

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

parameter=value&also=another

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


我忘记了文件上传是不同的(+1/接受)。您的回答就足够了,如果有更多关于 multipart/form-data 的信息就更好了。不过,对于那些感兴趣的人,这里是 a question about it
注意:正文与标题仅用一个空行分隔。
您解释了我们在 HTTPBody 中放置的内容,但是我们在 HTTPHeader 中放置/写入了什么?它的用途是什么?
@Honey:post 的 HTTP 标头看起来像 get 的标头,但使用动词 POST 而不是 GET,以及内容类型值(和可选的内容长度值),因为请求具有内容(正文)。每种类型的请求都有一个标头,有些类型也有一个主体。
@KennethWorden 不,这些方法都不会正确发送 JSON。但是,您可以以使用 multipart/form-data 编码的格式上传 json 文件,或者如果您负责请求构造,请将 content-type 更改为 application/json 并将 json 文本直接粘贴到 http 正文中
C
Camilo Martin

内容放在 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 请求和响应负载。


仅当内容类型为 application/x-www-form-urlencoded 时,情况并非总是如此。
Camilo Martin .... [+1] 提出了很好的问题和@Joe Alfano .... [+1] 提出了很好的答案......我现在对 POST 请求有了一个清晰的想法......但是如果图像带有键值对数据信息...... POST的结构是什么样的?
@Joe,现在你为什么会有一个 From 标题?
@Joe,我喜欢随机包含 From 标头。 IMO 它带有 418 HTTP 状态代码。
如何添加用户和密码身份验证?
C
Community

简短回答: 在 POST 请求中,值在请求的“正文”中发送。对于网络表单,它们最有可能使用 application/x-www-form-urlencodedmultipart/form-data 的媒体类型发送。设计用于处理网络请求的编程语言或框架通常对此类请求执行“正确的事情™”,并为您提供对易于解码的值的轻松访问(如 PHP 中的 $_REQUEST$_POST,或 {5 },flask.request.form 在 Python 中)。

现在让我们离题一点,这可能有助于理解其中的区别;)

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

GET(相关 RFC 部分)

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

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

请注意,键和值是 URI 的一部分。浏览器可能对 URI 长度施加限制。 HTTP 标准声明没有限制。但在撰写本文时,大多数浏览器确实限制了 URI(我没有具体的值)。 GET 请求应该永远用于向服务器提交新信息。特别是不是更大的文件。这就是您应该使用 POSTPUT 的地方。

POST(相关 RFC 部分)

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

POST 稍微复杂一些(方式更灵活):

接收 POST 请求时,您应该始终期待“有效负载”,或者用 HTTP 术语来说:message body。消息体本身没什么用,因为没有标准(据我所知。也许是application/octet-stream?)格式。正文格式由 Content-Type 标头定义。当使用带有 method="POST" 的 HTML FORM 元素时,这通常是 application/x-www-form-urlencoded。如果您使用文件上传,另一种非常常见的类型是 multipart/form-data。但它可以是任何东西,范围从 text/plain、超过 application/json 甚至是自定义 application/octet-stream

在任何情况下,如果使用应用程序无法处理的 Content-Type 发出 POST 请求,它应该返回 415 status-code

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

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

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

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

PUT(相关 RFC 部分)

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

相比之下,PUT 请求应该将资源准确地“存放”在 那个 URI 上,并用 exactly 那个内容。不多也不少。这个想法是 client 负责在“PUT”之前制作 complete 资源。服务器应该在给定的 URL 上按原样接受它。

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

边注

还有“path parameters”可以用来向遥控器发送额外的数据,但它们太少见了,我不会在这里详细介绍。但是,作为参考,这里是 RFC 的摘录:

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


我可能确实有点切线。我在答案的顶部添加了一个“tl;dr”,这应该更清楚。
我刚刚还对其进行了编辑以引用 RFC7231 而不是 RFC2616(它已经过时了一段时间)。除了更新的链接之外,此答案的主要区别在于“PUT”部分。
我认为 PUT 的处理方式与 POST 不同,因为它应该是幂等的? stackoverflow.com/questions/611906/…
@rogerdpack 你没有错。如果您阅读 PUT 部分的第二段,您会发现它 幂等的。 POST 相反可以——根据定义——不是。 POST 将始终创建新资源。如果存在相同的资源,PUT 将替换它。因此,如果您调用 POST 10 次,您将创建 10 个资源。如果您调用 PUT 10 次,它(可能)只会创建一个。这是否回答你的问题?
D
Denilson Sá Maia

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

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

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

将是帖子值。


澄清:Content-Length 应该是 29 吗?这是字符串 username=zurfyx&pass=password 的实际长度。
@Hippo 是一个换行符吗?
@vikingsteve 我明白你的意思。所以我猜内容的末尾总是有一个换行符。
标题与正文分开,带有额外的换行符
P
Peter Mortensen

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

例如:

Name: John Smith
Grade: 19

被编码为:

Name=John+Smith&Grade=19

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


您解释了我们在 HTTPBody 中放置的内容,但是我们在 HTTPHeader 中放置/写入了什么?
您提到密钥可以重复,那么这种重复的结果是什么?最后一个会自动覆盖以前的值吗?谢谢。
@JinghuiNiu 如果密钥重复,则应将其解析为数组。这很晚,但可能会帮助其他人。
S
SLaks

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

有关详细信息,请参阅 spec


“相同格式”有点模棱两可。例如,它们是否以 ? 开头?
@PeterWooster 是的,但没有提供示例。在这方面,就像一个答案说“看,在应用程序的博客(链接)中有你的问题的答案”。
@PeterWooster这不是必需的,但是当您忘记某些东西时,它非常好,谷歌它,转到第一个链接,这是SO,并且有一个清晰,简洁的示例可以告诉您您需要什么,而不是让您咀嚼过于详细的规格,即使是全面的,也可能不适合复习。想一想:这个网站上的大多数 QA 都可以归结为“去阅读规范/手册/API/等(链接)”。会有用吗?不超过谷歌。
仅当内容类型为 application/x-www-form-urlencoded 时,情况并非总是如此。
GET 查询字符串的格式与 application/x-www-form-urlencoded 的格式不同。例如,空格的编码方式不同(%20 vs +)。答案在这方面具有误导性。
I
Interface Unknown

某些 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

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

请注意:HTTP/1.1 被包装,左侧是 #32(空格),右侧是 #10(换行符)。


/user/john/?user=john 之间的区别只是语义上的区别(HTTP 并没有真正对查询字符串进行特殊处理),所以我认为这是合理的预期。但是“被左边的空格包裹”是什么意思? HTTP 方法之前没有空格。你的意思是帖子正文的空白行?
上述代码中的 ...Ym04HTTP/1.1 之间有一个空格(ASCII #32)。所以 QueryString 只是驻留在动词和协议版本之间。
您的注释听起来像是出乎意料且特定于版本的东西。坦率地说,那里似乎很明显有一个空间。换行符也适用于其他行,就像所有的 unix 一样。
我只是强调了我无法在代码中标出的内容。这可能看起来很明显,但有时并非如此。
确实,我们可以通过使用 ? 分隔 URI 和参数来将查询参数作为 URL 的一部分传递,就像我们对 GET 请求所做的那样。
S
Sudip Bhattarai

首先,让我们区分 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 来说是一个真正的问题。

通常,服务器对 URI 的长度有限制。如果发送的参数过多,您可能会收到 414 错误 - URI 太长

在发布请求的情况下,您将字段中的数据添加到正文中。计算请求参数的长度,并将其添加到 content-length 的 header 中,并且没有重要数据直接附加到 URL。

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

您可以随时在 Request Headers 中添加更多值,例如 Cache-ControlOriginAccept


有关安全性的假设仅在 HTTPS 连接的上下文中成立,而不是 HTTPHTTPS 同时加密 URL(包括查询参数)和 Request Body,而 HTTP 既不加密/保护也不加密。所描述的问题来自这样一个事实,即许多浏览器将 URIs(包括 URLs)存储在其历史数据库中(通常未加密)。因此,对于任何敏感内容,请仅使用 Request Body+HTTPS
@PetruZaharia 我同意你的解释。您也可以建议将此作为编辑,我很乐意接受! :)
I
Irakli Shalamberidze

post参数有多种方式/格式

表单数据

原始数据

json

编码数据

文件

xml

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


您的答案如何扩展或澄清此问题的任何其他答案?
A
Ahmad Ismail

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

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