Drupal 8 如何为发布后取消发布的页面设置410状态码
Drupal 8 实现曾发布后取消的节点返回410状态码方案
这个需求完全可以实现,核心逻辑是给节点增加「是否曾经正式发布过」的永久标记,再拦截未发布节点的默认404响应,根据标记区分返回410还是404。
具体实现步骤
1. 新增节点历史发布标记
你可以选择两种方式加标记:
- 后台可视化操作:在内容类型管理页,给需要适配的内容类型新增布尔类型字段
field_ever_published,默认值设为FALSE,设置字段对所有用户隐藏、不可手动编辑。 - 自定义模块钩子实现:不需要后台操作,直接在自定义模块中用
hook_node_presave()实现标记自动更新,节点只要被发布过一次,标记就会永久设为TRUE,后续取消发布也不会变更。
示例代码:function your_custom_module_node_presave(Drupal\node\NodeInterface $node) { if ($node->isPublished() && empty($node->get('field_ever_published')->value)) { $node->set('field_ever_published', TRUE); } }
2. 注册事件订阅器拦截响应
在自定义模块中注册事件订阅器,监听kernel.exception事件,当Drupal触发404异常时,判断当前访问的资源是否为「已被取消发布、且曾经发布过」的节点,如果匹配就返回410状态码,其余场景保留默认404。
核心示例代码:
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpFoundation\Response; public function onKernelException(GetResponseForExceptionEvent $event) { $exception = $event->getThrowable(); // 只处理404异常场景 if (!$exception instanceof NotFoundHttpException) { return; } $request_path = $event->getRequest()->getPathInfo(); // 先处理路径别名转内部节点路径 $internal_path = \Drupal::service('path_alias.manager')->getPathByAlias($request_path); // 匹配节点路径格式 if (preg_match('/^\/node\/(\d+)/', $internal_path, $match_result)) { $node = \Drupal\node\Entity\Node::load($match_result[1]); // 校验节点存在、未发布、且曾经发布过 if ($node && !$node->isPublished() && !empty($node->get('field_ever_published')->value)) { $response = new Response(); $response->setStatusCode(410); // 可自定义410页面的展示内容 $response->setContent('<h1>页面已永久移除</h1>'); $event->setResponse($response); } } }
3. 历史数据兼容
如果需要适配站点已有的、此前曾经发布过现在已经取消的节点,可以直接执行批量更新SQL,把这类节点的field_ever_published字段值统一设为1即可。
零代码替代方案
如果不想写自定义代码,也可以结合Rules模块和Redirect模块的可视化规则配置实现同样的效果,不需要改代码。
内容的提问来源于stack exchange,提问作者L.wadii
相关产品推荐
相关产品推荐

