【Phoenix】请求的生命周期

本文的目的是讨论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 ,应该会看到下面的页面:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp app tabbar 页面默认隐藏

1.在page.json 中找到tabbar visible 默认为true,设为false则是不显示 uni.setTabBarItem({ index: 1, //列表索引 visible:true //显示或隐藏 })

【C++】-- 红黑树详解

目录 一、红黑树概念 1.概念 2.性质 二、红黑树定义 1.红黑树节点定义 &#xff08;1&#xff09;将新插入节点置为红色 &#xff08;2&#xff09;将新插入节点置为黑色 2.红黑树定义 三、红黑树插入 1.插入节点 2.控制颜色 &#xff08;1&#xff09;父亲为黑色 &#xff0…

Games104现代游戏引擎笔记 面向数据编程与任务系统

Basics of Parallel Programming 并行编程的基础 核达到了上限&#xff0c;无法越做越快&#xff0c;只能通过更多的核来解决问题 Process 进程 有独立的存储单元&#xff0c;系统去管理&#xff0c;需要通过特殊机制去交换信息 Thread 线程 在进程之内&#xff0c;共享了内存…

如何在 Nginx Proxy Manager(NPM)上部署静态网站

前言 众所周知&#xff0c;我们在之前介绍过 Nginx Proxy Manager&#xff08;以下简称 NPM) 这个反向代理的神器&#xff0c;对于一些 Docker 搭建的 Web 项目&#xff0c;NPM 能够很轻松地给他们做反向代理。 然而对于一些静态网站&#xff0c;小伙伴们可能不知道怎么用 NP…

15分钟,不,用模板做数据可视化只需5分钟

测试显示&#xff0c;一个对奥威BI软件不太熟悉的人来开发数据可视化报表&#xff0c;要15分钟&#xff0c;而当这个人去套用数据可视化模板做报表&#xff0c;只需5分钟&#xff01; 数据可视化模板是奥威BI上的一个特色功能板块。用户下载后更新数据源&#xff0c;立即就能获…

LeetCode【560】和为k的子数组

题目&#xff1a; 思路&#xff1a; 转化为前缀和问题&#xff0c;和为k&#xff0c;即为&#xff1a;前缀和差值为k的情况统计&#xff1b; 为什么要转化为前缀和呢&#xff1f;因为和为k的子数组可能有n个元素&#xff0c;但是前缀和差值为k&#xff0c;只有两个元素&#…

微机原理_9

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

HTTP1.1协议详解

目录 协议介绍协议的特点存在的问题协议优化方案与HTTP 1.0协议的区别 协议介绍 HTTP 1.1是一种基于文本的互联网实体信息交互协议&#xff0c;是Web上任何数据交换和客户端-服务器交互的基础。它允许获取各种类型的资源&#xff0c;如HTML文档&#xff0c;并支持在互联网上交…

系列三、双亲委派机制

一、概述 当一个类收到了类加载的请求&#xff0c;它首先不会尝试自己去加载这个类&#xff0c;而是把这个请求委派给父类去完成&#xff0c;每一层的类加载器都是如此&#xff0c;因此所有的请求都应该传送到启动类加载器中&#xff0c;只有当父类加载器反馈自己无法完成这个…

arcgis--创建多分辨率DEM

方法一&#xff1a;技术链为【栅格转点】-【创建TIN】-【TIN转栅格】。首先需要将栅格转成点数据&#xff0c;再根据点数据创建TIN&#xff0c;再将TIN转栅格。 1、打开一幅DEM影像图&#xff0c;如下&#xff1a; 在【转换工具】-【由栅格转出】 -【栅格转点】工具中&#xf…

设计模式(4)-行为型模式

行为型模式 行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式&#xff0c;前者采用继承机制来在类间…

LeetCode(18)整数转罗马数字【数组/字符串】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 12. 整数转罗马数字 1.题目 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X …

SpringBoot--中间件技术-4:整合Shiro,Shiro基于会话SessionManager实现分布式认证,附案例含源代码!

SpringBoot整合安全中间件Shiro 技术栈&#xff1a;SpringBootShiro 代码实现 pom文件加坐标 Springboot版本选择2.7.14 &#xff1b;java版本1.8 &#xff1b; shiro做了版本锁定 1.3.2 <properties><java.version>1.8</java.version><!--shiro版本锁定…

鸿蒙:从0到“Hello Harmony”

效果展示 一.概述 明年华为鸿蒙就不再兼容Android生态了&#xff0c;作为拥有7亿终端用户的华为&#xff0c;建立自己的生态也是理所当然。 所以对HarmonyOS的研究也是众多开发者绕不开的坎了。 今天这篇博文主要实现一个“Hello Harmony&#xff01;”的Demo。 二.官方链接…

ChatGLM3-6B:新一代开源双语对话语言模型,流畅对话与低部署门槛再升级

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

SystemVerilog学习 (6)——验证平台

一、概述 测试平台&#xff08;Testbench&#xff09;是整个验证系统的总称。它包含了验证系统的各个组件、组件之间的互联关系&#xff0c;测试平台的配置与控制等&#xff0c; 从更系统的意义来讲&#xff0c;它还包括编译仿真的流程、结果分析报告和覆盖率检查等。 从狭义上…

【ArcGIS Pro二次开发】(76):面积平差工具

之前做过一个【三调土地利用现状分类面积汇总】的工具&#xff0c;在流程中使用了面积平差的方法。 考虑了在其它场合可能也需要进行面积平差&#xff0c;因此单独提取出来作为一个工具。 平差实现的方法如下图&#xff1a; 主要的计算过程如上图所示&#xff0c;算出总面积差…

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

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

总结1057

考研倒计38天 极限冲刺day1 今日共计学习13h33m&#xff0c;为了能走出备考的低谷阶段&#xff0c;来一场与自我的较量。在尽可能保证效率的情况下&#xff0c;玩命干。考研这件事&#xff0c;从来不是因为看到了希望才去努力&#xff0c;而是玩命努力后才看到希望。

通过IP地理位置阻止网络攻击

随着网络技术的不断发展&#xff0c;网络安全问题日益引起人们的关注。网络攻击者往往隐藏在虚拟的网络世界中&#xff0c;难以追踪其真实身份和位置。然而&#xff0c;近年来技术专家们借助IP地址定位的方法来阻止网络被攻击&#xff0c;这种方法引起了广泛关注。本文将探讨通…