首页 >后端开发 >php教程 >从请求到响应:前往Drupal 8内部的旅程

从请求到响应:前往Drupal 8内部的旅程

Jennifer Aniston
Jennifer Aniston原创
2025-02-17 11:11:38957浏览

深入Drupal 8(和Symfony2)内部:请求到响应的流程

核心要点

  • Drupal 8 利用Symfony2 的HTTPKernel 和HTTPFoundation 组件来处理用户请求和响应,以面向对象的方式封装请求、将其传递给应用程序并返回响应。
  • HTTPKernel 组件是任何基于Symfony 的应用程序的核心,它在index.php 文件中启动流程,并利用由事件驱动的流程。这使得应用程序更灵活,任务可以委托给这些事件的监听器。
  • 如果控制器没有返回Response 对象,内核会触发kernel.view 事件,订阅者负责将控制器的结果转换为实际的Response 对象。这种灵活性允许控制器返回任何类型的对象,只要它与将对象转换为正确Response 的VIEW 事件订阅者相结合。
  • HTMLRenderer 作为最常用的主内容渲染器类型,使用页面变体的概念构建页面。此过程发生在HTMLRenderer 的prepare() 方法中,该方法为renderResponse() 方法提供一个#type => 'page' 渲染数组,该数组包装了主内容。然后将其包装到#type => 'html' 渲染数组中,并使用Renderer 类进行渲染。

在关于Drupal 8 模块开发的第一篇文章中,我们稍微了解了此过程的路由方面。我们已经看到,创建带有路径的页面现在只是声明与控制器匹配的路由的问题。正如我们所看到的,后者可以返回一个渲染数组,该数组被解释为标记并在该页面的主要内容区域中显示。但是,您是否知道,在幕后,Drupal 实际上根据Symfony 的HTTPKernelInterface 的规定将该数组转换为Response 对象?

From Request to Response: A Journey into Drupal 8 Internals

在本文中,我想让我们更深入地了解Drupal 8(和Symfony2)的内部结构,并了解从用户发出请求到他们看到返回的响应的时刻之间实际发生的事情(以及可能发生的事情)。我上面提到的示例只是此过程可以进行的一个方向,今天我们还将看到其他可能性。目标是了解系统的灵活性,这反过来可以帮助我们构建出色的应用程序。

在深入研究之前,我强烈建议您查看此图表,它在综合通常被称为渲染管道的内容方面做得非常出色。尽管在我看来,它代表的内容比名称所暗示的更多,因为渲染系统只是图中所描绘的一部分,尽管是一大部分。

前端控制器 (index.php)

Symfony2 现在是Drupal 的重要组成部分,这已不是什么秘密。后者使用了许多Symfony 的组件,对本文而言最重要的组件是HTTPKernel 和HTTPFoundation 组件。它们共同负责封装用户请求,将其传递给应用程序,然后以一致且面向对象的方式将返回的内容返回给用户。

HTTPKernelInterface(您可能也从其他上下文中听说过)通过接收Request 对象并始终返回Response 对象来将所有这些粘合在一起。一个非常简单但功能强大的概念。

此过程在index.php 文件内部启动,该文件首先生成所述Request 对象并将其传递给HTTPKernel::handle() 方法。然后,后者负责返回Response 对象。从高层次来看,这在Drupal 应用程序和Symfony 应用程序(或任何其他利用HTTPKernel 组件的应用程序)中都会发生。

HTTPKernel 和事件

HTTPKernel 是任何基于Symfony 的应用程序的核心。正如我们所看到的,它的handle() 方法在准备响应方面负有很大的责任,并且它以由事件驱动的流程来做到这一点。这使得应用程序非常灵活,繁重的工作总是委托给这些事件的监听器。

如果您查看之前的图表,您可以看到此工作流程在第二列中进行了描述,它基本上代表了Symfony 和Drupal 方面的粘合剂。

它从第一个名为kernel.request 的事件开始。此事件的订阅者处理各种任务。但在Drupal 8 中,两个非常重要的任务是格式协商和路由。第一个确定需要返回的响应类型(html、json、图像、pdf 等),第二个确定负责处理此响应的代码(routing.yml 文件内路由定义的_controller 密钥)。但是,就像此事件工作流程中的大多数步骤一样,如果侦听器返回response 对象,则该过程会跳过大部分后续步骤(停止传播)并直接转到kernel.response。

第二个事件是kernel.controller,它在应用程序知道哪个控制器负责处理请求后被调用。此时,侦听器仍然可以对其执行一些覆盖操作。紧随此步骤之后,内核负责解析传递给控制器的参数。Drupal 中的一个这样的操作是根据请求中找到的ID(例如节点)加载对象,并直接向控制器提供这些对象。然后,控制器最终会使用相应的参数被调用。

控制器负责返回某种响应。如果它返回Response 对象,则该过程会跳到kernel.response 事件。后者的侦听器可以对对象执行最后一分钟的修改,例如修改标头或内容本身。并且在从handle() 方法获取它之后,前端控制器使用Response 对象上的send() 方法将其发送回用户并终止该过程。

From Request to Response: A Journey into Drupal 8 Internals

更深入地了解渲染数组

如果控制器没有返回Response 对象,则内核会触发最后一个事件:kernel.view。它的订阅者负责将控制器的结果转换为实际的Response 对象。因此,这意味着您可以从控制器返回任何类型的对象,只要您将其与将该对象转换为正确的Response 的VIEW 事件订阅者相结合即可。

但是,正如我们在示例中看到的,控制器大多数时候会返回渲染数组。这通常表示页面的主要内容(类似于Drupal 7 中的页面回调)。

为了处理这个问题,Drupal 8 有一个MainContentViewSubscriber 负责将此数组转换为正确的Response 对象。它通过使用在前面讨论过的格式协商阶段选择的特定MainContentRenderer 来做到这一点。尽管已经有一些这样的渲染器可用,但使用的默认渲染器是HtmlRenderer。

HTMLRenderer

由于这是最常用的主内容渲染器类型,因此让我们更深入地了解一下它是如何构建页面的。

此过程中的一个很酷的事情是页面变体的概念。这意味着HTMLRenderer 分派一个负责找出要使用哪种类型的页面来包装主内容渲染数组的事件:RenderEvents::SELECT_PAGE_DISPLAY_VARIANT。默认情况下,除非启用了Block 模块,否则使用SimplePageVariant。在这种情况下,BlockPageVariant 会启动并允许在主要内容周围的区域中放置块。如果需要,您可以在自己的模块中订阅此事件并提供您自己的变体。

所有这些都发生在HTMLRenderer 的prepare() 方法中,该方法为renderResponse() 方法提供一个#type => 'page' 渲染数组,该数组包装了主内容数组。后两者依次被包装到#type => 'html' 渲染数组中,该数组最终使用Renderer 类(Drupal 7 中drupal_render() 的等效项)进行渲染。生成的HTML 字符串将添加到Response 对象中并返回给前端控制器。

虽然这是对该过程非常高级别的概述,但这基本上就是发生的事情。现在我们有一个Response 对象,这意味着内核可以分派其kernel.response 事件。之后,前端控制器可以直接将Response 发送回用户并终止该过程。

结论

在本文中,我们通过跟踪从用户请求到服务器返回的响应的管道,对Drupal 8(和Symfony2)内部进行了探索。我们已经看到Drupal 8 如何利用HTTPKernel 和HTTPFoundation Symfony2 组件,以及它基本上如何位于这些组件之上。此外,我们还看到了它们之间的粘合剂是如何由内核分派的事件组成的,Drupal 为其所有功能订阅了这些事件。最后,我们已经看到如何在渲染管道的帮助下构建并返回HTML 页面给用户。

我相信了解Drupal 8 应用程序中幕后发生的事情将使您能够通过准确了解进入此流程的入口点来创建出色的应用程序。我相信,如果您只从本文中带走一件事情,那应该是灵活性这个词。因为在Drupal 8 中构建我们所需内容的灵活性远远超过Drupal 7 中的任何内容。它确实已经变得现代化了。

关于Drupal 8 内部结构的常见问题解答 (FAQ)

Drupal 7 和Drupal 8 的主要区别是什么?

与Drupal 7 相比,Drupal 8 引入了几个重大变化。它有一个名为Twig 的新的主题引擎,它更安全、更灵活。Drupal 8 也更适合移动设备,并且包含更多内置字段。它更好地支持多语言站点,具有改进的语言管理和翻译支持。此外,由于广泛使用Symfony 组件,Drupal 8 与第三方平台的集成更好。

Drupal 8 如何处理请求和响应?

Drupal 8 使用Symfony HttpKernel 组件来处理请求和响应。当发出请求时,Drupal 8 会创建一个Request 对象并将其传递给HttpKernel。然后,HttpKernel 使用路由系统来确定哪个控制器应该处理该请求。控制器处理请求并返回一个Response 对象,HttpKernel 将其发送回客户端。

路由系统在Drupal 8 中的作用是什么?

Drupal 8 中的路由系统负责将URL 映射到特定的控制器。它使用模块提供的路由定义来确定哪个控制器应该处理给定的请求。路由系统还支持动态路由,这些路由可以根据系统的状态而改变。

Drupal 8 的主题系统如何工作?

Drupal 8 的主题系统使用Twig,这是一个灵活且安全的模板引擎。Drupal 8 中的主题由一个.info.yml 文件(提供有关主题的元数据)和Twig 模板文件(定义HTML 输出)组成。主题系统还支持模板继承,允许主题扩展和覆盖来自其他主题或模块的模板。

我如何在Drupal 8 中开发自定义模块?

在Drupal 8 中开发自定义模块包括创建一个.info.yml 文件来提供有关模块的元数据,以及一个.module 文件来包含模块的PHP 代码。模块还可以包含其他文件,例如定义路由的路由文件和定义服务的服务文件。Drupal 8 使用面向对象编程和Symfony 组件,使编写可重用和可测试的代码更容易。

使用Drupal 8 进行Web 开发的好处是什么?

Drupal 8 为Web 开发提供了许多好处。它使用Symfony 组件使其更加强大和灵活。它开箱即用地支持响应式设计,使创建移动友好型网站更容易。Drupal 8 还改进了多语言支持、更好的SEO 功能和更用户友好的管理界面。

Drupal 8 如何处理数据库交互?

Drupal 8 使用数据库API 来处理数据库交互。数据库API 在SQL 之上提供了一个抽象层,允许开发人员编写数据库查询而无需了解底层数据库引擎的细节。它还支持动态查询、事务和模式管理。

事件调度程序在Drupal 8 中的作用是什么?

Drupal 8 中的事件调度程序用于管理事件和事件侦听器。当发生事件时,事件调度程序会通知所有已注册的侦听器,然后这些侦听器可以采取行动。这允许模块以解耦的方式相互交互。

Drupal 8 如何处理缓存?

Drupal 8 具有一个复杂的缓存系统,有助于提高性能。它支持多个缓存后端,包括基于数据库、文件和内存的后端。Drupal 8 还具有缓存标记系统,允许对缓存数据进行细粒度的失效。

我如何扩展Drupal 8 的功能?

Drupal 8 的功能可以通过模块和主题来扩展。模块添加新功能或修改现有功能,而主题控制站点的外观和感觉。Drupal 8 还支持插件,允许交换功能部件,以及服务,提供可重用的功能,可以注入到系统的其他部分。

This revised output maintains the original meaning while rephrasing sentences and paragraphs, avoiding direct copying. The image URLs are preserved. The formatting is adjusted for better readability.

以上是从请求到响应:前往Drupal 8内部的旅程的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn