当前位置: 首页 > news >正文

【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, :routerpipeline :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_headersendpipeline :api do plug :accepts, ["json"]endscope "/", HelloWeb do pipe_through :browserget "/", 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 :browserget "/", 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, :controllerdef 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, :htmlend

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

通过函数添加代码如下:

defmodule HelloWeb.HelloHTML do use HelloWeb, :htmldef 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, :htmlembed_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: :helloplug 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 :browserget "/", PageController, :homeget "/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 ,应该会看到下面的页面:

在这里插入图片描述

相关文章:

【Phoenix】请求的生命周期

本文的目的是讨论Phoenix请求的生命周期。我们实战添加两个新的页面&#xff0c;并讨论整个过程是如何串起来的。 让我们从添加第一个新页面开始。 添加一个新页面 web应用通常通过将HTTP方法和路径映射到应用的某个函数来处理请求。Phoenix通过路由器来实现这个匹配。例如将…...

Ps:利用 AI 技术创建人像皮肤图层蒙版

Photoshop 并没有提供专门选择人像皮肤的工具或命令&#xff08;色彩范围中的肤色选择非常不精准&#xff09;&#xff0c;但较新版的 Camera Raw 滤镜则提供了基于 AI 技术的选择人物并创建面部和身体皮肤蒙版的功能。 如果能将 Camera Raw 滤镜中创建的 AI 皮肤蒙版转换成 Ps…...

内存泄漏、new、delete

1. 内存泄漏 内存泄漏&#xff1a;指针被销毁&#xff0c;指针指向的空间依旧存在 2. new过程 与内存分配、构造函数有关 1&#xff09;分配空间&#xff1a;void* mem operator new( sizeof( ) )&#xff0c;内部调用malloc 2&#xff09;static_cast<目标类型>(mem) …...

php在线审稿系统mysql数据库web结构layUI布局apache计算机软件工程网页wamp

一、源码特点 php在线审稿系统是一套完善的web设计系统mysql数据库 &#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 php在线审稿系统 代码 https://download.csdn.net/download/qq_41221322/885…...

【华为HCIP | 华为数通工程师】ISIS 高频题(1)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…...

Netty+SpringBoot 打造一个 TCP 长连接通讯方案

项目背景 最近公司某物联网项目需要使用socket长连接进行消息通讯&#xff0c;捣鼓了一版代码上线&#xff0c;结果BUG不断&#xff0c;本猿寝食难安&#xff0c;于是求助度娘&#xff0c;数日未眠项目终于平稳运行了&#xff0c;本着开源共享的精神&#xff0c;本猿把项目代码…...

2023.11.15 每日一题(AI自生成应用)【C++】【Python】【Java】【Go】 动态路径分析

目录 一、题目 二、解决方法 三、改进 一、题目 背景&#xff1a; 在一个城市中&#xff0c;有数个交通节点&#xff0c;每个节点间有双向道路相连。每条道路具有一个初始权重&#xff0c;代表通行该路段的成本&#xff08;例如时间、费用等&#xff09;。随着时间的变化&am…...

【libGDX】初识libGDX

1 前言 libGDX 是一个开源且跨平台的 Java 游戏开发框架&#xff0c;于 2010 年 3 月 11 日推出 0.1 版本&#xff0c;它通过 OpenGL ES 2.0/3.0 渲染图像&#xff0c;支持 Windows、Linux、macOS、Android、iOS、Web 等平台&#xff0c;提供了统一的 API&#xff0c;用户只需要…...

VIVADO+FPGA调试记录

vivadoFPGA调试记录 vitis编译vivado导出的硬件平台&#xff0c;提示xxxx.h file cant find vitis编译vivado导出的硬件平台&#xff0c;提示’xxxx.h file cant find’ 此硬件平台中&#xff0c;包含有AXI接口类型的ip。在vitis编译硬件平台时&#xff0c;经常会报错&#xf…...

Android——Gradle插件gradle-wrapper.properties

一、Android Studio版本&#xff0c;Android Gradle插件版本&#xff0c;Gradle版本 Android Studio 通过Android Gradle插件 使用 Gradle来构建代码&#xff1b; Android Studio每次升级后&#xff0c; Android Gradle 插件自动更新&#xff0c;对应的Gradle版本也会变动&…...

iOS应用加固方案解析:ipa加固安全技术全面评测

在移动应用开发领域&#xff0c;iOS应用的安全性一直备受关注。ipaguard作为一款专业的iOS应用加固方案&#xff0c;采用混淆加密技术&#xff0c;旨在保护应用免受破解、逆向和篡改等风险。本文将深入探讨ipaguard的产品功能、安全技术及其在iOS应用加固领域中的核心优势和特色…...

过滤器模式 rust和java的实现

文章目录 过滤器模式实现 过滤器模式实现javarustjavarust rust代码仓库 过滤器模式 过滤器模式&#xff08;Filter Pattern&#xff09;或标准模式&#xff08;Criteria Pattern&#xff09;是一种设计模式&#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;部分…...

Python3基础模块 random

Python3基础模块 random import random #作用&#xff1a;生成随机数使用dir(module)查看模块内容 >>> import random >>> dir(random) [BPF, LOG4, NV_MAGICCONST, RECIP_BPF, Random, SG_MAGICCONST, SystemRandom, TWOPI, _BuiltinMethodType, _MethodT…...

ubuntu安装pgsql16

ubuntu安装postgresSQL 官网地址&#xff1a; https://www.postgresql.org/download/ 1.安装 # 添加源 sudo sh -c echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list # 安装数字签名 w…...

数据管理70个名词解析

数据标准化70个名词解析 1、数据 是指任何以电子或者其他方式对信息的记录。在计算机科学技术中&#xff0c;“数据”是客观事物的符号表示&#xff0c;指所有可被输入到计算机中并可被计算机程序处理的符号的总称;在管理科学技术中&#xff0c;“数据”是描述事件或事物的属性…...

线性代数本质系列(二)矩阵乘法与复合线性变换,行列式,三维空间线性变换

本系列文章将从下面不同角度解析线性代数的本质&#xff0c;本文是本系列第二篇 向量究竟是什么&#xff1f; 向量的线性组合&#xff0c;基与线性相关 矩阵与线性相关 矩阵乘法与复合线性变换 三维空间中的线性变换 行列式 逆矩阵&#xff0c;列空间&#xff0c;秩与零空间 克…...

Linux-CentOS重要模块

软件包管理器&#xff1a;CentOS使用Yum&#xff08;Yellowdog Updater, Modified&#xff09;作为其包管理器。Yum提供了一种方便的方式来安装、更新和删除软件包&#xff0c;并自动解决依赖关系。 RPM&#xff1a;RPM&#xff08;RPM Package Manager&#xff09;是CentOS中…...

posix定时器的使用

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

安科瑞煤矿电力监控系统的研究与应用

摘要&#xff1a;作为一个巨大的能源消耗国家&#xff0c;我国每年对煤炭的市场需求巨大。煤炭作为我国点力气和供暖企业的重要原材料&#xff0c;煤矿的开采过程存在着难以消除的风险&#xff0c;我国的煤炭安全问题长期困扰着相关企业和监督部门&#xff0c;也受到社会的广泛…...

高教社杯数模竞赛特辑论文篇-2023年A题:基于机理分析法的定日镜场优化设计模型(附获奖论文及MATLAB代码实现)

目录 摘要 一、 问题重述 1 . 1 问题背景 1 . 2 问题要求 二、 问题分析...

缩点+图论路径网络流:1114T4

http://cplusoj.com/d/senior/p/SS231114D 重新梳理一下题目 我们先建图 x → y x\to y x→y&#xff0c;然后对点分类&#xff1a;原串出现点&#xff0c;原串未出现点。 假如我们对一个原串出现点进行了操作&#xff0c;那么它剩余所有出边我们立刻去操作必然没有影响。所…...

Go语言fyne开发桌面应用程序-环境安装

环境安装 参考https://developer.fyne.io/started/#prerequisites网站 之前的文章介绍了如何安装GO语言这里不在叙述 msys2 首先安装msys2&#xff0c;https://www.msys2.org/ 开始菜单打开MSYS2 执行 $ pacman -Syu$ pacman -S git mingw-w64-x86_64-toolchain注意&#…...

JavaWeb——CSS3的使用

目录 1. CSS概述 2. CSS引入方式 3. CSS颜色显示 4. CSS选择器 4.1. 元素&#xff08;标签&#xff09;选择器 4.2. id选择器 4.3. 类选择器 4.4. 三者优先级 5. 盒子模型 1. CSS概述 CSS&#xff0c;全称为“Cascading Style Sheets”&#xff0c;中文译为“层叠样式…...

AR导览小程序开发方案

一、背景介绍 随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;技术逐渐被应用于各个领域。其中&#xff0c;AR导览小程序作为一种新兴的导览方式&#xff0c;以其独特的视觉体验和互动性受到了广泛的关注。AR导览小程…...

继承、多态

复习 需求&#xff1a; 编写一个抽象类&#xff1a;职员Employee,其中定义showSalary(int s)抽象方法&#xff1b;编写Employee的子类&#xff0c;分别是销售员Sales和经理Manager,分别在子类中实现对父类抽象方法的重写&#xff0c;并编写测试类Test查看输出结果 package cn.…...

贪吃蛇小游戏代码

框架区 package 结果;import java.awt.Color; import java.awt.EventQueue; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.util.ArrayList; import java.util.List; import java.util.Random;import javax.s…...

Python数据容器(字典)

字典 1.字典的定义2.字典数据的获取3.字典的嵌套4.嵌套字典的内容获取5.字典的常用操作6.常用操作总结7.遍历字典8.练习 1.字典的定义 同样使用{}&#xff0c;不过存储的元素是一个一个的&#xff1a;键值对&#xff0c;语法如下 # 定义字典字面量 {key:value,key:value,...,…...

餐饮展示小程序的作用是什么

餐饮是市场重要的组成部分&#xff0c;尤其是我国八大菜系&#xff0c;各类细分菜数量非常多&#xff0c;并分布在全国&#xff0c;各类大小品牌餐饮商家数量也非常庞大&#xff0c;每个城市的商业街都是一个接一个餐厅&#xff0c;酒类、酒店多样。 餐饮行业经营痛点比较明显…...

33、Flink 的Table API 和 SQL 中的时区

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...