我在 etc/schema.graphqls 里新增了字段,文件也已经上传,GraphQL Playground 还是回答 Cannot query field。这时最容易进入“清缓存抽奖”:cache:clean、cache:flush、重启 Redis 全来一遍,偶尔好了,却不知道为什么。

我现在按两个问题拆:运行中的 Magento 有没有读到这份 schema?客户端拿到的是不是当前 schema?

第一步:确认文件确实属于已启用模块

php bin/magento module:status Vendor_Module
php bin/magento setup:db:status
grep -R "my_new_field" app/code/Vendor/Module/etc vendor/vendor-name/module-name/etc

路径必须是模块的 etc/schema.graphqls,文件名、大小写和部署包都要一致。新模块若没有完成注册、启用或 setup upgrade,schema 内容再正确也不会参与合并。

多节点环境再加一项:在每台实际接流量的节点计算该文件校验值。只发布到一台时,请求会一会儿认识字段、一会儿不认识,表现得很像缓存。

第二步:先只加一个最小字段

复杂 schema 有时是类型扩展位置写错,或者 resolver 配置让加载失败。先缩成一个不会依赖业务数据的字段,确认它能出现在 introspection 中,再逐步加参数、返回类型和 resolver。这样比同时调 schema、DI 和业务 SQL 快得多。

同时查看 var/log/exception.log、system.log 和 PHP 日志。schema 合并错误有时在构建或首次请求就已经记录,前端只显示一句泛化错误。

清哪类缓存才有意义

schema 定义属于服务配置的一部分,开发环境可以先定向清理 Magento 的 config cache,再请求 introspection 验证:

php bin/magento cache:clean config
php bin/magento cache:status

如果项目启用了生产编译,新增 resolver 类、构造参数或 DI 配置后,还要按项目标准重新编译和部署。cache:flush 不会替你生成缺失的 compiled code。

graphql_query_resolver_result 缓存保存的是可缓存 resolver 的结果,不是所有 schema 变更的万能开关。字段连 introspection 都不存在时,先处理模块加载与 config schema,不要把注意力放在业务结果缓存上。

最后排除“其实是客户端旧 schema”

IDE 和前端代码生成工具会缓存 introspection。直接用 curl 向实际 /graphql 端点发一个最小查询;如果服务端已认识字段,而 IDE 仍标红,刷新 schema 或重启代码生成工具即可。还要确认请求域名、Store header 和环境没指到另一套站点。

我的验收顺序是:introspection 能找到字段;最小查询能调用 resolver;带真实参数的查询返回正确数据;关闭开发日志后在所有节点重复请求。这样每一步只验证一个层次,不需要靠“再清一次全部缓存”碰运气。