【Phoenix】请求的生命周期

news2024/11/26 12:26:32

本文的目的是讨论Phoenix请求的生命周期。我们实战添加两个新的页面,并讨论整个过程是如何串起来的。

让我们从添加第一个新页面开始。

添加一个新页面

web应用通常通过将HTTP方法和路径映射到应用的某个函数来处理请求。Phoenix通过路由器来实现这个匹配。例如将”/articles”映射到显示文章的函数。因此,添加一个页面首先要添加一个新的路由。

新建路由

控制器和动作通过路由器关联它要处理的HTTP方法和路径。在Phoenix中,控制器对应者Elixir的模块,动作是控制器下定义的方法。

动作本质上就是一个处理请求的函数,在Go语言中,称为处理器函数,Phoenix使用了”action”一词来表述它,翻译为动作确实略显生硬,阅读时可以理解为每个请求对应的动作。但对于其本质一定要拿捏准确。

对于新的应用,Phoenix为我们生成了一个路由器文件 lib/hello_web/router.ex ,它也是本章的主角。

在前面例子中欢迎页的路由如下:

get "/", PageController, :home

让我们看看这个路由干了什么。访问 http://localhost:4000 向跟目录发起一个HTTP GET请求。这个请求会被 lib/hello_web/controllers/page_controller.ex 文件定义的 HelloWeb.PageController 中的 home/2 函数处理。

我们会新建一个页面,当访问 http://localhost:4000/hello 时,输出”Hello World, from Phoenix!”。

我们要做的第一件事是添加一个页面路由。打开 lib/hello_web/router.ex ,对于一个全新的应用,内容如下:

defmodule HelloWeb.Router do 
	use HelloWeb, :router
	pipeline :browser do 
		plug :accepts, ["html"] 
		plug :fetch_session 
		plug :fetch_live_flash 
		plug :put_root_layout, html: {HelloWeb.Layouts, :root} 
		plug :protect_from_forgery 
		plug :put_secure_browser_headers
	end
	pipeline :api do 
		plug :accepts, ["json"]
	end
	scope "/", HelloWeb do 
		pipe_through :browser

		get "/", PageController, :home 
	end
	# Other scopes may use custom stacks. 
	# scope "/api", HelloWeb do 
	# pipe_through :api 
	# end
	# ... 
end

暂时忽略 pipelinescope ,在稍后的教程中再讨论它们。

让我们在 scope "/" do 下添加一个路由,将 GET /hello 请求映射到 HelloWeb.HelloControllerindex 方法。

scope "/", HelloWeb do 
	pipe_through :browser

	get "/", PageController, :home 
	get "/hello", HelloController, :index
end

新建controller

控制器是Elixir模块,动作是模块下的Elixir函数。动作的目的是收集数据并执行渲染。我们需要一个 HelloWeb.HelloController 模块以及一个 index/2 函数。那么动手创建一个 lib/hello_web/controllers/hello_controller.ex 文件,并输入下面的代码:

defmodule HelloWeb.HelloController do 
	use HelloWeb, :controller
	
	def index(conn, _params) do 
		render(conn, :index)
	end 
end

use HelloWeb:controller 再后面的教程中再详细讨论,先将注意力集中到 index 函数。

一个控制器动作有两个参数,第一个是 conn ,它是一个存储着大量请求数据的结构体;第二个是 params ,它是请求参数。这里为了避免编译器警告,我们在 params 前面加了一个下划线 _

函数的核心是 render(conn, :index) ,它告诉Phoenix要渲染 index 模板。表示渲染的模块叫做视图,Phoenix视图默认控制器和视图格式来命名,这里控制器是 HelloController ,视图格式是 HTML ,因此我们需要一个 HelloWeb.HelloHTML 模块并定义个 index/1 函数。

新建视图

Phoenix视图充当的是展示层。例如,我们希望 index 输出的是完整的HTML页面。为了快乐搬砖,我们常常会用模板创建HTML页面。

让我们来创建一个视图,新建 lib/hello_web/controllers/hello_html.ex 文件,输入以下代码:

defmodule HelloWeb.HelloHTML do 
	use HelloWeb, :html

end

我们可以通过函数或者单独的文件向视图添加模板。

通过函数添加代码如下:

defmodule HelloWeb.HelloHTML do 
	use HelloWeb, :html

	def index(assigns) do 
		~H"""
		Hello! 
		"""
	end 
end

我们定义了一个接受 assigns 的函数,并使用 ~H 标记添加想要渲染的内容。在 ~H 标记内,我们使用的模板语言叫HEEx,表示”HTML+EEx”。EEx是一个用来嵌入Elixir的库,HTML+EEx是EEx针对HTML的扩展,支持HTML验证,组件,和值的自动转义。后者可使你免受跨站点脚本之类的安全漏洞的影响,而无需额外的工作。

模板文件原理类似。函数方式适用于短小的模板,模板文件适用于有很多标签或当你感觉函数已难以维护时。

让我们试着定义一个模板文件。首先删除 def index(assigns) 函数定义,替换成 embed_templates 声明:

defmodule HelloWeb.HelloHTML do 
	use HelloWeb, :html

	embed_templates "hello_html/*" 
end

这里我们告诉 Phoenix.Component 将同级目录 hello_html 下的所有 .heex 模板做为函数定义嵌入我们的模块。

接下来我们需要向 lib/hello_web/controllers/hello_html 目录添加文件。

注意看控制器名称 HelloController ,视图名称 HelloHTML 和模板目录 hello_html 都遵循着相同的命名约定,并且它们在目录树中也在一起。

注意:我们可以任意重命名 hello_html 目录并将它放在 lib/hello_web/controllers 子目录下,但是需要更新 embed_templates 设置。因此建议保持统一的命名约定以避免歧义。

lib/hello_web

├── controllers

│·····├── hello_controller.ex

│·····├── hello_html.ex

│·····├── hello_html

|·············├── index.html.heex

模板文件名格式为 NAME.FORMAT.TEMPLATING_LANGUAGE ,我们在 lib/hello_web/controllers/hello_html/ 目录下创建一个名为 index.html.heex 的文件:

<section> 
	<h2>Hello World, from Phoenix!</h2>
</section>

模板文件会自行编译为模块下的函数,两种方式没有运行时的性能差异。

现在我们有了路由,控制器,视图和模板,我们可以访问 http://localhost:4000/hello 来看看效果了。

在这里插入图片描述

这里有些有趣的事情值得我们注意。当我们做这些变更时,不需要停止和重启服务器。没错,Phoenix具有代码热加载!还有即使我们的 index.html.heex 文件只包含一个简单的 section 标签,我们也得到了一个完整的HTML文档。事实上我们的模板是渲染在一个布局中的:首先渲染的是 lib/hello_web/components/layouts/root.html.heex ,然后它会渲染 lib/hello_web/components/layouts/app.html.heex ,最后是我们的内容。如果你打开这些文件看一看,就会在底部发现这样一行代码:

<%= @inner_content %>

它会在HTML被发送到浏览器之前将模板注入到布局中。关于布局我们会在后面的教程中介绍。

从endpoint到视图

我们已经创建了第一个页面,现在可以看看一个请求的生命周期是如何串联起来的了。

所有的HTTP请求都始于应用的endpoint,其实就是 lib/hello_web/endpoint.ex 文件中的 HelloWeb.Endpoint 模块。当我们打开这个文件查看时,就会发现它里面大量调用了 plug ,跟路由挺像的。Plug是一个库,也是组织web应用的说明书。它是Phoenix处理请求的重要部分,有关细节后面的教程中会讲到。

目前,可以说每个plug都定义了一个处理请求的队列。在endpoint中,你会看到大致如下的框架:

defmodule HelloWeb.Endpoint do 
	use Phoenix.Endpoint, otp_app: :hello

	plug Plug.Static, ... 
	plug Plug.RequestId 
	plug Plug.Telemetry, ... 
	plug Plug.Parsers, ... 
	plug Plug.MethodOverride 
	plug Plug.Head 
	plug Plug.Session, ... 
	plug HelloWeb.Router
end

每个插件都有不同的作用,后面我们会讲到。最后一个插件恰好就是 HelloWeb.Router 模块。它让endpoint将所有请求的后续处理都交给路由器。路由器的主要作用就是将请求映射到处理器。最后处理器告诉视图渲染一个模板。

此时,你可能会想,简单地渲染一个页面怎么需要这么多步骤。但是,当应用变得越来越复杂时,我们会看到每一层都有其特殊的作用:

  • endpoint(Phoenix.Endpoint) - endpoint包含所有请求的公共和初始路径,用来处理所有请求都要做的事情。
  • 路由器(Phoenix.Router) - 路由负责将请求分发到控制器,同时也运行我们确定一些功能的范围。比如有些页面需要用户鉴权,有些页面则不需要。
  • 控制器(Phoenix.Controller) - 控制器的工作是提取请求信息,调用业务领域,并为表示层准备数据。
  • 视图 - 视图处理来自控制器的结构化数据,并将其转换为显示给用户的形式。视图通常以它们呈现的内容格式命名。

让我们再添加一个页面,巩固一下最后三个组件是如何协同工作的。

这里我保留了endpoint这个单词,本意为端点、终点,直译不好理解,这里endpoint指的其实就是服务端,或者说是服务所有请求的入口点。

创建新页面

让我们稍微加一点难度,添加一个页面,它会截取URL的一部分并通过控制器传入模板,最后在页面上显示出来。

如前面说的,我们首先要做的是创建一个新的路由。

创建新路由

这里我们复用之前创建的 HelloController ,添加一个新的 show 方法。在之前的路由下添加一行:

scope "/", HelloWeb do 
	pipe_through :browser

	get "/", PageController, :home
	get "/hello", HelloController, :index 
	get "/hello/:messenger", HelloController, :show
end

注意我们在路径中用到了 :messenger 语法,Phoenix会将URL中对应位置的值转成一个变量。例如,我们在浏览器输入 http://localhost:4000/hello/Frank ,messenger的值就是Frank。

新建动作

新路由下的请求会由 HelloWeb.HelloControllershow 函数处理。我们已经有了一个控制器 lib/hello_web/controllers/hello_controller.ex ,因此我们唯一需要做的就是在控制器下添加一个 show 函数。这一次,我们需要从参数中提取messenger变量,并传递给模板。为此,将下面的函数添加到控制器:

def show(conn, %{"messenger" => messenger}) do 
	render(conn, :show, messenger: messenger)
end

我们给 render 函数传递了第三个参数,一个键值对。其中 :messenger 是键,变量 messenger 是值。

如果我们需要访问除messenger之外的请求参数,可以像下面这样定义 show/2 函数

def show(conn, %{"messenger" => messenger} = params) do 
	...
end

要记住, params 的键是字符串,等号不是赋值,而是模式匹配。

新建模板

最后我们需要创建一个新的模板,遵循命名规范,将它放在 lib/hello_web/controllers/hello_html 目录下,命名为 show.html.heex 。唯一与 index.html.heex 不同的是,这次我们需要显示messenger变量。

为此,我们使用特殊的HEEx标签 <%= %> 来求值Elixir表达式。任何出现在标签内的Elixir代码都会被执行,其结果会替换该标签。如果标签内没有等号,代码依然会被执行,但结果不会出现在页面中。

记住我们的模板是用HEEx(HTML+EEx)编写的,HEEx是EEx的超集,因此也继承了 <%= %> 语法。

模板内容如下:

<section>
	<h2>Hello World, from <%= @messenger %>!</h2>
</section>

我们从控制器传入视图的值统称为”assigns”,我们可以通过 assigns.messenger 来访问messenger,但是通过元编程,Phoenix为我们提供了更加干净的 @ 语法。

完成。如果我们用浏览器访问 http://localhost:4000/hello/Frank ,应该会看到下面的页面:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1213533.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蒙HarmonyOS从零实现类微信app效果第二篇,我的+发现页面实现

本着不拖更的原则&#xff0c;今天上新了&#xff0c;今天实现了类微信app的发现页和我的页面。先看效果。 效果是不是看着还不错。其实这两个页面功能实现还是比较简单的&#xff0c;接下来还是老规矩&#xff0c;先进行页面的拆分和代码实现&#xff0c;然后进行相关我认为比…

嵌入式linux--sysfs文件系统以及操作GPIO

sysfs文件系统 在Linux系统中&#xff0c;/sys路径是一个特殊的虚拟文件系统&#xff08;Virtual File System&#xff09;&#xff0c;用于提供对内核和设备的运行时信息的访问。它是sysfs文件系统的挂载点&#xff0c;提供了一种以文件和目录形式表示系统设备、总线、驱动程…

【Web开发】基于 Jekyll 中的 Chirpy 模板搭建博客网站(一):成功经验篇

基于 Jekyll 中的 Chirpy 模板搭建博客网站&#xff08;一&#xff09;&#xff1a;成功经验篇 1.Jekyll 介绍2.Chirpy 介绍3.安装步骤3.1 Prerequisites3.2 Installation3.2.1 Creating a New Site3.2.2 Installing Dependencies 3.3 Usage3.3.1 Configuration3.3.2 Running L…

使用C#插件Quartz.Net定时执行CMD任务工具2

目录 创建简易控制台定时任务步骤完整程序 创建简易控制台定时任务 创建winform的可以看&#xff1a;https://blog.csdn.net/wayhb/article/details/134279205 步骤 创建控制台程序 使用vs2019新建项目&#xff0c;控制台程序&#xff0c;使用.net4.7.2项目右键&#xff08…

ubuntu下C++调用matplotlibcpp进行画图(超详细)

目录 一、换源 二、安装必要的软件 三、下载matplotlibcpp 四、下载anaconda 1.anaconda下载 2.使用anaconda配置环境 五、下载CLion 1.下载解压CLion 2.替换jbr文件夹 3.安装CLion 4.激活CLion 5.CLion汉化 6.Clion配置 六、使用CLion运行 七、总结 我的环…

posix定时器的使用

POSIX定时器是基于POSIX标准定义的一组函数&#xff0c;用于实现在Linux系统中创建和管理定时器。POSIX定时器提供了一种相对较高的精度&#xff0c;可用于实现毫秒级别的定时功能。 POSIX定时器的主要函数包括&#xff1a; timer_create()&#xff1a;用于创建一个定时器对象…

Kubernetes(k8s)介绍和环境部署

文章目录 Kubernetes一、Kubernetes介绍1.Kubernetes简介2.Kubernetes概念3.Kubernetes功能4.Kubernetes工作原理5.kubernetes组件6.Kubernetes优缺点 二、Kubernetes环境部署环境基本配置1.所有节点安装docker2.所有节点安装kubeadm、kubelet、kubectl添加yum源containerd配置…

LeetCode(16)接雨水【数组/字符串】【困难】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 42. 接雨水 1.题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&…

PbootCMS 应用快速迁移至浪潮信息 KeyarchOS 云服务器

本文我们以 PbootCMS 应用为例&#xff0c;详细介绍如何使用 X2Keyarch 迁移工具将其从 CentOS 系统迁移到浪潮信息 KeyarchOS 系统。 背景介绍 众所周知&#xff0c;CentOS 是最流行的红帽克隆版&#xff0c;因为免费&#xff0c;所以它的安装量甚至比红帽本身要大得多。本来…

Feature Pyramid Networks for Object Detection(2017.4)

文章目录 Abstract1. Introduction3. Feature Pyramid NetworksBottom-up pathwayTop-down pathway and lateral connections 7. Conclusion FPN Abstract 特征金字塔是识别系统中检测不同尺度物体的基本组成部分。但最近的深度学习对象检测器避免了金字塔表示&#xff0c;部分…

python科研绘图:绘制X-bar图

目录 1.X-bar 图的基本概念 2.X-bar 图的绘制过程 3.X-bar 图的优势 4.X-bar 图的绘制 1.X-bar 图的基本概念 X-bar控制图是一种统计工具&#xff0c;用于监控和控制生产过程中的质量变量。它是过程能力分析和统计过程控制&#xff08;SPC&#xff0c;Statistical Process…

微机原理_9

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案。 1.当运算结果的最高位为1时&#xff0c;标志位(&#xff09; A. CF1 B. OF1 C. SF1 D. ZF1 2、汇编语言源程序中,每个语句由四项组成,如语句要完成一定功能,那么该语句中不可…

构造函数和初始化列表的关系和区别【详解】

构造函数和初始化列表关系和区别&#xff0c;以及为什么有初始化列表&#xff0c;和它的好处 一、构造函数和初始化列表的关系和区别二、为什么有初始化列表三、使用初始化列表的好处 一、构造函数和初始化列表的关系和区别 百度百科这样定义初始化列表&#xff1a;与其他函数…

使用手机作为电脑的麦克风和摄像头外设

工具 Iriun Iriun 电脑端安装&#xff1a;Iriun Android: Iriun 4K Webcam for PC and Mac - Apps on Google Play Apple: Iriun Webcam for PC and Mac on the App Store 基础功能免费&#xff0c;普通使用足够了。 付费功能&#xff1a; 使用 这里有介绍&#xff1a…

【Java】详解多线程同步的三种方式

&#x1f33a;个人主页&#xff1a;Dawn黎明开始 &#x1f380;系列专栏&#xff1a;Java ⭐每日一句&#xff1a;等风来&#xff0c;不如追风去 &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️ 文章目录 一.&#x1f510;线…

MAC地址_MAC地址格式_以太网的MAC帧_详解

MAC地址 全世界的每块网卡在出厂前都有一个唯一的代码,称为介质访问控制(MAC)地址 一.网络适配器(网卡) 要将计算机连接到以太网&#xff0c;需要使用相应的网络适配器(Adapter)&#xff0c;网络适配器一般简称为“网卡”。在计算机内部&#xff0c;网卡与CPU之间的通信&…

【UE C++】读取文本文件,并解析

目录 0 引言1 空格 制表符 换行符1.1 定义1.2 查看字符 2 实战 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;UE虚幻引擎专栏&#x1f4a5; 标题&#xff1a;❣️ 寄语&#xff1a;书到用时方恨少&#xff0c;事非经过不知难&#xff01;&#x…

C进阶---字符函数和字符串函数

目录 一、长度不受限限制的字符串函数 1.1strlen 1.2strcpy 1.3strcat 1.4strcmp 二、长度受限制的字符串函数 2.1strncpy 2.2strncat 2.3strncmp 三、其他字符串函数 3.1strstr 3.2strtok 3.3sterror 3.4memcpy 3.5memmove 3.6memcmp 四、字符分类函…

c语言:如何打印杨辉三角形。

题目&#xff1a;打印杨辉三角形 如&#xff1a; 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 思路和代码&#xff1a; //由规律不难得出&#xff0c;每行首个数字和最后最后一个数字都为1&#xff0c;其余数字是这列的上一个数字和前一个数字的和组成&#xff0c;由此推出代码 #de…

Openssl X509 v3 AuthorityKeyIdentifier实验与逻辑分析

Openssl是X509的事实标准&#xff0c;目前主流OS或个别安全性要求较高的设计场景&#xff0c;对X509的证书链验证已经不在停留在只从数字签名校验了&#xff0c;也就是仅仅从公钥验签的角度&#xff0c;在这些场景中&#xff0c;往往还会校验AuthorityKeyIdentifier和SubjectKe…