API Platform 自定义操作中禁用读取监听器的正确配置方法
技术百科
霞舞
发布时间:2026-01-19
浏览: 次 在 api platform 中为自定义操作(如 `/cards/random`)禁用默认 `readlistener` 时,必须将该操作声明在内置 `get` 操作之前,否则框架仍会尝试执行读取逻辑并返回 404 错误。
API Platform 的 ReadListener 会在请求生命周期中根据操作类型自动触发读取逻辑(例如通过 ID 加载实体)。当你定义一个非标准的 itemOperation(如 random),即使显式设置了 "read" => false,如果该操作位于内置 'get' 之后,API Platform 仍可能因路由匹配或操作解析顺序问题,错误地将其识别为需执行读取的 item 操作,从而调用 ReadListener 并因无法解析 {id} 而抛出 Not Found(404)。
根本原因在于:API Platform 对 itemOperations 的处理存在隐式优先级——当路径形如 /cards/random 且未包含 {id} 占位符时,若 random 操作排在 'get' 之后,框架可能跳过对该自定义操作的精确匹配,转而尝试按 get 的规则(要求 id 参数)进行解析,最终失败。
✅ 正确做法是:将自定义操作声明在所有依赖 ID 的内置操作(如 'get', 'put', 'delete')之前,确保其路由和配置被优先识别:
#[ApiResource(
itemOperations: [
// ✅ 自定义操作必须置于 'get' 之前
'random' => [
'method' => 'GET',
'path' => '/cards/random',
'controller' => CardRandomController::class,
'read' => false, // 明确禁用 ReadListener
'openapi_context' => [
'summary' => 'Get a random card',
'parameters' => [], // 注意:此处不应声明 "id" 参数,因路径无 {id}
],
],
'get', // ⚠️ 必须放在 custom operation 之后
'put',
'patch',
'delete',
],
denormalizationContext: ['groups' => 'card:write'],
normalizationContext
: ['groups' => 'card:read'],
)]
class Card
{
// ...
}⚠️ 同时注意以下关键细节:
- openapi_context['parameters'] 中不应包含 "id" 字段(除非路径含 {id}),否则 OpenAPI 文档会错误提示必需参数;
- 清除缓存(bin/console cache:clear)是必要步骤,但顺序问题无法通过清缓存解决;
- 控制器返回值需与 normalizationContext 兼容(本例中 Card 实体需支持 card:read 序列化组);
- 若后续需支持集合级随机操作,应使用 collectionOperations 而非 itemOperations。
总结:"read" => false 本身有效,但其生效前提是 API Platform 能正确识别并路由到该自定义操作——而操作声明顺序,正是决定这一识别是否成功的隐式契约。
# 放在
# 会在
# 将其
# 排在
# 这一
# 当你
# 不应
# 自定义
# 而非
# 路由
# console
# delete
# 隐式
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Windows 11怎么设置默认解压软件_Wind
- 如何在Golang中配置代码格式化工具_使用gof
- Windows 11如何查看系统激活密钥_Wind
- c++的static关键字有什么用 静态变量和静态
- Windows服务启动类型恢复方法_错误修改导致的
- Win11怎么更改系统语言为中文_Windows1
- MAC的“接续互通”功能无法使用怎么办_MAC检查
- Windows执行文件被SmartScreen拦截
- 如何在Golang中编写端到端测试_Golang
- Windows10系统怎么查看显卡型号_Win10
- c# Task.Yield 的作用是什么 它和Ta
- Python大型项目拆分策略_模块化解析【教程】
- php订单日志怎么按金额排序_php按订单金额排序
- php删除数据怎么清空表_truncate与del
- Win11怎么设置开机密码_Windows11账户
- Win11怎么修改DNS服务器 Win11设置DN
- php中::能访问全局变量吗_全局作用域与类作用域
- 如何在 Go 中正确反序列化多个同级 XML 元素
- php订单日志怎么记录物流_php记录订单物流变更
- Win11怎么自动隐藏任务栏_Win11全屏显示设
- Mac如何创建和管理多个桌面空间_Mac高效多任务
- Mac如何查看电池健康百分比_Mac系统信息电源检
- 如何使用Golang实现错误包装与传递_Golan
- Win11怎么设置指纹解锁 Win11笔记本录入指
- WindowsUSB驱动安装异常怎么办_USB驱动
- Windows电脑如何截屏?(四种快捷方法)
- 如何用正则与预处理结合精准拦截拼接式垃圾域名
- Win11怎么查看显卡显存_查询Win11显卡详细
- c++获取当前时间戳_c++ time函数使用详解
- Win10怎样卸载DockerDesktop_Wi
- Python数据挖掘核心算法实践_聚类分类与特征工
- c++如何判断文件是否存在_c++ filesys
- mac怎么安装pip_MAC Python pip
- 如何在 Go 中创建包含映射(map)的切片(sl
- Windows10如何更改桌面背景_Win10个性
- Python文件操作优化_大文件与流处理解析【教程
- c# 如何深拷贝和浅拷贝
- Windows 10怎么录屏_Windows 10
- Mac系统更新下载慢或失败怎么办_解决macOS升
- c++中explicit(bool)的用法 c++
- C++中的std::shared_from_thi
- 如何在Golang中实现自定义Benchmark_
- Windows怎样关闭桌面弹窗广告_Windows
- Win11怎么打开注册表_Windows 11注册
- php打包exe后无法读取环境变量_变量配置方法【
- c# 如何用c#实现一个支持优先级的任务队列
- Python日志系统设计与实现_高可观测性架构实战
- Win11怎么设置单手模式_Win11触控键盘布局
- Win10系统字体模糊怎么办_Windows10高
- Win11键盘快捷键大全_Windows 11常用


QQ客服