【问题标题】:PSR-7: getParsedBody() vs getBody()PSR-7:getParsedBody() 与 getBody()
【发布时间】:2020-02-06 18:54:21
【问题描述】:

场景1发送x-www-form-urlencoded数据

POST /path HTTP/1.1
Content-Type: application/x-www-form-urlencoded

foo=bar

运行print_r($request->getParsedBody()); 返回正常:

Array
(
    [foo] => bar
)

运行print_r($request->getBody()->getContents());会返回一个字符串foo=bar


场景2发送application/json数据

POST /path HTTP/1.1
Content-Type: application/json

{
    "foo": "bar"
}

运行 print_r($request->getParsedBody()); 返回一个空数组。 Array ( )

但是,运行 print_r($request->getBody()->getContents()); 返回正常:

{"foo":"bar"}


这是预期的行为吗?

意思是,如果我们发送x-www-form-urlencoded数据,我们应该使用getParsedBody()

如果我们发送application/json,则应该使用getBody()->getContents()


其他信息:

请求对象的创建使用:

$request = \Laminas\Diactoros\ServerRequestFactory::fromGlobals(
        $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES
);

【问题讨论】:

  • 1) 您使用的是哪个 PSR-7 库 - 可能是 zend diactoros? 2) 对于每个场景,您应该提供构建 ServerRequest 对象的代码。 3) 对于“场景 1”:您是否也尝试过使用类似 $content = (string) ($request->getBody()); echo $content; 的方式激活 StreamInterface::__toString 方法?我问这个是因为StreamInterface::__toString 方法实现“必须在读取数据之前尝试寻找流的开头”,而StreamInterface::getContents“返回剩余的 字符串中的内容".
  • @dakis 实际上,场景 1 似乎在使用 $request->getBody()->getContents() 时实际上返回了一个字符串 foo=bar。我已经更新了场景。还包括如何创建请求对象。

标签: php json post http-post psr-7


【解决方案1】:

邮件正文:

在 PSR-7 库中,消息正文StreamInterface 抽象。此接口的任何实现都必须包装PHP stream,当然,应该提供适当的功能来对其执行特定的读/写/查找操作。 PHP 提供了一个 I/O 列表streams,其中php://input 适用于相关任务。

php://input 是一个只读流,允许您从请求正文中读取原始数据。 php://input 不适用于 enctype="multipart/form-data"

在这种情况下,当对服务器执行请求时,请求主体数据(无论其数据类型如何)会自动以原始格式(字符串)写入php://input 流。稍后可以通过调用StreamInterface::getContentsStreamInterface::__toStringStreamInterface::read(在其实现中可能会使用stream_get_contents() 或类似名称)从中读取信息。

注意:方法StreamInterface::__toString在表示消息体的对象时自动调用,例如实现StreamInterface 的类的实例被强制转换为字符串。例如,像这样 - 请参阅 PHP 中的 Type Casting

$messageBodyObject = $request->getBody(); // implements StreamInterface
$contentOfMessageBody = (string) $messageBodyObject; // cast to string => StreamInterface::__toString is called

echo $contentOfMessageBody;

解析后的正文:

关于 PSR-7,解析的主体是应用程序的“特征”,其中 PHP “用作服务器端应用程序来满足 HTTP 请求” em>(与使用 PHP 作为“HTTP 客户端” 的应用程序相比)- 参见 Summary of the PSR-7 Meta Document。所以,解析后的正文只是ServerRequestInterface的一个组件。

解析后的主体(读取 ServerRequestInterface::getParsedBodyServerRequestInterface::withParsedBody 的 cmets)被认为是原始数据(字符串)的“解析”形式(数组或对象)的表示形式) 作为执行请求的结果保存在php://input 流中。例如,$_POST variable 是一个数组,在以下条件下保存 POST 请求的已解析主体

相关用例:

如果执行 POST 请求并且标头 Content-Typeapplication/x-www-form-urlencoded(例如提交普通 HTML 表单时),则请求正文的内容会自动保存到 php://input 流(序列化)和$_POST 变量(数组)。因此,在 PSR-7 上下文中,同时调用 StreamInterface::getContents(或 StreamInterface::__toString,或 StreamInterface::read)和 ServerRequestInterface::getParsedBody 将返回“有效”值。

如果执行 POST 请求并且标头 Content-Typemultipart/form-data(例如执行文件上传时),则请求正文的内容根本不会保存到 php://input 流中,但仅限于 $_POST 变量(数组)。因此,在 PSR-7 上下文中,只有调用 ServerRequestInterface::getParsedBody 才会返回“有效”值。

如果执行 POST 请求,并且标头 Content-Type 的值不同于上述两个值(例如 application/jsontext/plain; charset=utf-8),则请求正文的内容仅保存到 php://input溪流。因此,在 PSR-7 上下文中,只有调用 StreamInterface::getContents(或 StreamInterface::__toString,或 StreamInterface::read)才会返回“有效”值。

资源:

【讨论】:

  • (string) $request->getBody(); // 返回原始 json 有效负载,只要 $request 正在实现 ServerRequestInterface
  • @pofqggg 你好。谢谢。但是,您能否更准确地告诉我/我们什么?
  • 只是总结您在该主题上写的内容。要从请求对象中获取原始有效负载,请实现 ServerRequestInterface - (string) $request->getBody();是方式
  • @pofqggg 不错的建议。再次感谢你。我用它完成了我的回答。
猜你喜欢
  • 2019-03-27
  • 2016-02-24
  • 2014-07-25
  • 1970-01-01
  • 2017-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多