会,webman的$request->json()默认全量加载请求体再json_decode,遇50mb json极易oom;必须绕过该方法,改用php://input流式读取配合jsonstreamingparser等流式解析器逐段处理。

Webman里用$request->json()解析大JSON会OOM吗
会,而且非常容易。Webman默认把整个请求体读进内存再json_decode,如果前端发个50MB的JSON(比如导出报表、批量设备配置),PHP进程直接内存爆掉,Worker崩溃退出。
关键不是Webman本身的问题,而是它底层依赖的 json_decode() 是全量加载模式——没流式解析、不支持分块、不做内存限制。
- 别指望
$request->json()自动处理大体积数据,它只是封装了json_decode(file_get_contents('php://input'), true) - Webman没有内置流式JSON解析器,必须自己接管原始输入流
- PHP 8.3+ 的
JsonStreamingParser扩展可用,但Webman项目通常不预装,需手动编译启用
如何安全读取并逐段解析超大JSON请求体
绕过 $request->json(),直接从 php://input 流读取,配合 json_decode() 的 JSON_PARTIAL_OUTPUT(PHP 8.4+)或第三方流式库。生产环境推荐用 ralouphie/json-stream。
- 先检查
Content-Length头:超过 2MB 就拒绝或走异步流程,避免无脑接收 - 用
fopen('php://input', 'rb')获取只读流,配合stream_set_read_buffer($fp, 8192)控制每次读取大小 - 传给
JsonStreamingParser\Parser实例,注册onObjectStart/onValue回调处理关键字段,跳过无关嵌套 - 不要把整个JSON存成数组,解析完立刻写入数据库或Redis,释放内存
示例片段:
$fp = fopen('php://input', 'rb');
$parser = new \JsonStreamingParser\Parser($fp, new MyEventHandler());
$parser->parse();
Webman中间件里怎么拦截和校验大JSON的结构合法性
不能等走到控制器才校验,得在中间件层做轻量级 Schema 验证,防止无效JSON拖垮后续流程。
- 用
json_last_error()快速判断是否合法JSON,比json_decode()开销小得多 - 对已知关键字段(如
data、items)用正则粗筛是否存在,避免全量解析 - 限制顶层键数量:
substr_count(file_get_contents('php://input'), ':') 防止恶意构造超多字段 - 禁止深层嵌套:用
mb_substr_count($raw, '{') - mb_substr_count($raw, '}')监控括号不平衡,超过5层就中断
为什么用file_get_contents('php://input')仍可能失败
因为Webman在启动时可能已提前读取过输入流(比如启用了某些日志中间件或调试工具),导致 php://input 变为空。
- 确认没其他中间件调用过
$request->getBody()->getContents()或$request->getParsedBody() - 在中间件中优先使用
$request->getBody()->detach()获取原始流,而不是重复读取 - 若已 detach,后续控制器不能再用
$request->json(),必须自己完成解析逻辑 - 开发期开启
config/app.php中的'debug' => true会触发额外日志读取,上线前务必关闭
实际部署时最容易被忽略的是:大JSON场景下,你写的“校验中间件”和“解析控制器”必须共享同一个输入流实例,否则第二次读就是空的——这不是Webman的bug,是PHP流的特性。










