You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从PHP/PSR-7 ServerRequestInterface获取multipart payload子部分头

问题描述

发送multipart/form-data请求时,每个表单部分可携带额外请求头。例如以下curl命令:

curl -v --trace-ascii - -X POST https://dev-server/api/intake -H "Authorization: Bearer $token" -F 'data={"json":{"Yep": "this is JSON"}};type=application/json'

会生成如下HTTP请求:

POST /api/intake HTTP/2
Host: dev-server
User-Agent: curl/8.5.0
Accept: */*
Authorization: Bearer long-token-here
Content-Length: 213
Content-Type: multipart/form-data; boundary=------------------------lQNQ3xgpz1neU0tlQTPXnF

--------------------------lQNQ3xgpz1neU0tlQTPXnF
Content-Disposition: form-data; name="data"
Content-Type: application/json

{"json":{"Yep": "this is JSON"}}
--------------------------lQNQ3xgpz1neU0tlQTPXnF--

我用PHP实现API端点,通过PSR-7的ServerRequestInterface捕获请求数据,能通过$message->getParsedBody()获取data字段的JSON字符串,但无法获取其关联的Content-Type: application/json子头。

尝试自行解析请求体也未成功:

// 返回空字符串,推测是因为 multipart/form-data 请求下 php://input 不可用
$message->getBody()->getContents();
// 无法全局禁用 php.ini 中的 enable_post_data_reading 设置,
// 因为应用其他部分依赖它,且通过 ini_set 修改无效。

请问是否有官方支持的方式获取这些子部分头?(我知晓可将整个请求设为application/json,但这并非目标,我希望使用multipart请求。)

解决方案

PHP默认处理multipart/form-data请求时,仅解析表单字段内容与文件上传元数据,不会保留非文件字段的子头信息。基于PSR-7规范,可通过以下两种官方支持的方式解决:

1. 将字段标记为文件上传

在curl请求中给目标字段添加filename=标记(即使没有实际文件),PHP会将其识别为上传文件,子头信息会被保留:
修改后的curl命令:

curl -v --trace-ascii - -X POST https://dev-server/api/intake -H "Authorization: Bearer $token" -F 'data={"json":{"Yep": "this is JSON"}};type=application/json;filename='

或通过标准输入传递内容:

curl -v --trace-ascii - -X POST https://dev-server/api/intake -H "Authorization: Bearer $token" -F 'data=@-;type=application/json' <<<'{"json":{"Yep": "this is JSON"}}'

随后在PSR-7请求对象中,通过getUploadedFiles()方法获取子头与内容:

$uploadedFiles = $message->getUploadedFiles();
if (isset($uploadedFiles['data'])) {
    $contentType = $uploadedFiles['data']->getClientMediaType(); // 获取Content-Type
    $jsonContent = $uploadedFiles['data']->getStream()->getContents(); // 获取内容
}

2. 使用PSR-7兼容的请求解析库

若无法修改客户端请求,可使用成熟的PSR-7请求解析库(如symfony/http-foundation的PSR-7桥接工具、laminas/laminas-httphandlerrunner),这些库能完整解析multipart/form-data的所有子部分及其头信息。

以symfony/http-foundation为例,将PSR-7请求转换为Symfony Request后即可获取完整表单部分信息:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Psr7\HttpFoundationPsr7Bridge;

// 转换PSR-7请求为Symfony Request
$symfonyRequest = HttpFoundationPsr7Bridge::createRequest($message);
// 遍历所有表单部分
foreach ($symfonyRequest->getPayload()->getParts() as $part) {
    if ($part->getName() === 'data') {
        $contentType = $part->getHeaders()['Content-Type'][0];
        $content = $part->getBody()->getContents();
        break;
    }
}

这类库会自动处理php://input的读取时机,无需修改enable_post_data_reading配置。

内容的提问来源于stack exchange,提问作者DMJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 18:44:57