Ruby Rails是一个Web框架,包含许多您需要创建和部署成功的Web应用程序的库。我们经常授予Runds New以创建具有大量内置功能的全功能Web应用程序的能力。对于我们许多人来说,这已经足够了,因为铁路的目标是神奇地拥有一切都在不需要知道引擎盖下发生的事情。
为了在所有荣耀中完全欣赏Ruby,我们首先需要了解它试图解决的问题。让我们在一个不存在轨道的世界中。我知道,这很难。
我们如何仅使用标准的Ruby库构建Web应用程序?在本文中,我将分解Web应用程序如何在从地上建造一个的主要基础概念。如果我们只能使用Ruby库构建Web应用程序,为什么我们需要像Ruby在Raby上等机架和Web应用程序这样的Web服务器接口?到本文结束时,您将对Rails及其魔法获得新的欣赏。
我将涵盖主题,包括:网络协议(TCP和HTTP),持久数据存储,Web服务器接口(机架)和Rails库(操作控制器,动作调度,活动记录和操作视图)。在本教程的前半部分,我们只需使用核心Ruby库,这就足以了解Web应用程序如何工作原理的关键概念。在下半场,我们将使用Rails的模块替换代码。
我的假设写作是您,亲爱的读者,知道如何使用文件编辑器并导航终端。您还应该熟悉与Internet相关的条款,如Web浏览器。熟悉Ruby或Ruby在Rails和Data Structures上不是一个要求,但它会有所帮助!最后,假设你在带有麦克斯的计算机上跟随,并知道如何安装和使用Ruby Gems。
在任何情况下,我强烈建议使用代码样本并运行计算机上的代码以获得完整的学习体验。毕竟,没有经验没有学习。
我们今天将建立的Web应用程序被称为游束,一个Web应用程序,具有用户的功能,以查看显示的数据并输入将在应用程序中持久的新数据。你希望如何看待数据取决于您。本教程的欢乐Web应用程序将是生日跟踪器。而不是依靠某个社交媒体来告知我们人们的生日,你现在可以问他们,记录它并在列表中查看它。
现在我们有序得到了一切。让我们从Web应用程序如何运作的基础。 Web应用程序或服务器如何与互联网交谈?与人类一样,网络应用程序具有他们用于彼此通信的特定协议,称为传输控制协议(TCP)。您可能已经听过TCP之前,但TCP在Web应用程序中的作用是什么?
要了解TCP的表现,我们必须先了解互联网协议(IP)。你' ll很快发现抽象水平是了解这是如何工作的主题。 TCP只是一种IP的抽象,用于传输数据数据包的较低级别协议。
虽然IP是互联网如何运作的基础,但它是一个原始协议,因此不可靠。使用IP姿势风险,如错误的数据包交付顺序或根本没有送货。 TCP建于IP顶部,以使系统更可靠,具有附加功能。为解决超出数据包传输的问题,TCP允许发件人在接收器结束中重新组装的数据包内添加自动递增号。另一个关键特征TCP添加是套接字的概念。
套接字意味着表示服务器和客户端之间的持久连接。 Ruby有一个名为套接字的核心库,该套接字从操作系统(顺便说一下,又是另一种抽象!)。
套接字库允许您创建TCP服务器套接字。在我们的案例中,Lirth的服务器套接字想要留意任何传入连接。但是,连接如何知道应用程序的应用程序? TCP在特定端口上创建一个套接字,可以标识为使用它的应用程序。在这种情况下,我们指定欢乐的端口为1337。
既然创建了服务器套接字,我们决定在进行连接时要为客户端提供什么。在循环中,我们通过#accept接受任何客户端。一旦客户端被接受为连接,我们就会以IO对象的形式接收信息。
一旦您接受了客户的连接,您现在可以从客户端获取任何输入。在这种情况下,我们询问客户“您的名字是什么?”,并检索并反动修改后的回复。
要在计算机上运行此代码,请运行文件,ruby mirth-1.rb。通过这样做,您可以创建服务器套接字。现在,您需要一个客户端连接到服务器。
打开一个新的终端窗口并运行NC LocalHost 1337.您现在在使用NetCAT的端口号1337中连接到本地服务器插座。随后,在连接在代码中的打印语句中建立连接后输入任何输入。
既然你能够创建一个TCP套接字,您就可以进一步提升抽象。目前,我们的TCP服务器仍然无法使用浏览器正确通信。这是因为Web浏览器以一个名为Hyper文本传输协议(HTTP)的另一协议的语言说话。 TCP是应用程序不可知论,因此任何类型的应用都可以使用TCP。另一方面,http是特定于网络的。所以,我们可以在Ruby我们自己实施HTTP。
世界上有许多类型的浏览器和服务器,这就是我们拥有HTTP的原因。该协议由HTTP工作组设置,因此世界上每个人都可以在Web浏览器中以相同的语言发言。
HTTP消息专门为两种类型:请求和响应。 Web浏览器可以向服务器提出请求,并在其响应中使用所请求的页面授权。请求和响应之间的差异仅在HTTP消息的开始行中不同,其中请求具有请求行,响应具有状态行。这些请求和响应的结构在名为RFC的文档中详细说明。
从Mirth Web应用程序的角度来看,它希望在连接之后准备好在客户端提供所请求的信息。客户端现在将从前面示例中提供一串名称,而不是提供一个字符串,现在将使HTTP请求进行HTTP请求。
HTTP请求的关键组件是包含Web应用程序采取行动的重要信息的请求行。这些是令牌的方法,目标路径和HTTP协议版本号。该方法令牌是来自服务器的请求类型,两个常见的常见版本(以获取数据)和发布(到发布数据以在服务器中进行更改)。正如您所期望的那样,方法令牌将代码下调单独的路径,具体取决于所请求的内容。目标是请求来自的路径。例如,服务器从用户从请求信息向本页提供信息的目标路径,www.mith.com/baked -brownies/123是烘焙棕色/ 12。最后,版本号是Web浏览器正在使用的HTTP版本,最常见的是HTTP / 1.1。
一旦服务器接受客户端套接字,我们就会读取请求的请求行。与我们以前使用的#获取方法不同,#Readline如果没有更多的输入,则会返回错误。
我们将HTTP请求分解为零件,方法_Token,Target和Version_Number。所有这些部分都是服务器上如何响应请求的重要信息。该代码只需打印来自HTTP请求所获得的信息,并将其返回在HTTP请求正文中以在Web浏览器页面上显示。
我们不是从另一个套接字中提出请求,我们直接从浏览器提出请求。打开浏览器并输入localhost:1337 / cakes-and / pies。您的浏览器不会显示任何内容,因为服务器已响应并响应。相反,记下记录在输出中的字符串。
HTTP响应的第一部分是表示启动行的状态代码。在我们的情况下,我们希望确保浏览器一切顺利,所以我们制作状态代码201 OK。如果服务器有任何问题,则浏览器将能够将该信息中继到用户,该信息解释了访问Bad WebPage时最常见的404错误状态代码。
还有HTTP响应的其他值为标题字段。标题字段是密钥值对的行,在我们的情况下,内容类型:Text / HTML。您可以在RFC文档页面上找到其他标题列表。
标题字段的类型可能会在请求和响应之间变化,但是对于响应,标题是输入有关重定向,缓存和cookie的路径等响应的任何其他信息,以及与安全相关的详细信息。浏览器读取标题字段并相应地执行操作,例如重定向到相应的页面,存储相应的用户设置,或保护网页。
身体是您将Web浏览器呈现的HTML代码的位置。
好吧,让我们向我们的Web应用程序添加一些复杂性,并回复Web浏览器,具有我们自己的更好的HTTP响应。我们将添加一些模拟数据来显示(在本例中的出生日胎),以及两个HTTP响应以显示数据并使用新用户输入更新数据。
让我们首先创建一些默认数据。在服务器初始化之后就在哈希中找到的所有生日数据。请注意,数据不持久,含义一旦服务器重新启动,添加到此哈希的任何对象都会消失。
接下来,我们创建一个案例语句,以便分离不同的方法令牌和路径目标。这使我们为我们的小型Web应用程序提供了三个端点的清晰概述。三个端点是,获取/显示/生日,发布/添加/生日和任何其他通用路径。如果请求与任何端点匹配,则块中的代码将运行。
因为每个端点都会产生不同的HTTP响应,所以我们为每个端点定义以下变量,response_status_code,content_type和response_message。
至于POST方法,我们将一些用户输入添加到我们的生日数据哈希。目前,它不会持久,但您仍然能够在运行同一服务器时添加到列表中。
后端点与Get Endpoint看起来有点不同。此时状态代码不会是“200确定”,因为而不是刚通知浏览器该请求成功,我们可以使用“303查看其他”状态更有用的并将用户重定向到/ show /出生日页面代码。
接下来,请求中需要一个重要的标题字段,Contention-Length标题。内容长度标题是HTTP请求中的主体消息的大小以字节为单位。一旦我们知道邮件正文包含多少字节,我们将从客户端套接字的IO准确读取身体。最后,我们使用Ruby内置的解码器库,称为URI,将请求的身体解码为Ruby Hash,以便在我们的生日列表结束时追加。
一旦我们基于每个端点确定了HTTP响应的所有组件,我们都会重建响应。响应在HTTP规范之后构建:响应开始行包含版本号和响应状态代码,然后是标题,空行和响应主体。在下一次练习中,我们接受来自Web浏览器的GET和POST响应。
类似于上一个练习,我们向网址打开浏览器,但这一次我们去LocalHost:1337 / show /生日,是显示出生的网址。
在表单中添加新的生日信息,页面更新新数据。
按Control-C重新启动服务器关闭服务器并再次使用Ruby Mirth-3.RB运行它。重新启动使服务器从代码中提供的默认数据开始。
什么是Web应用程序,没有存储数据的能力?我们轻松收集并显示一些用户提交的数据,但一旦套接字关闭,它就不会粘在一起。我们需要一种方法来存储数据,所以下次服务器重新启动时,我们仍然可以使用先前保存的相同数据集。但我们会怎么样?
显然,答案是存储在数据库中。数据库存储有关物理磁盘或服务器的信息。但假装我们生活在一个数据库不存在的时代。持续一些信息的最原始方式是什么?我们将数据保存到文件中。
我们可以使用纯文本文件,但我们必须实现自己的格式,以表示纯文本中的数据。好消息是Ruby有一个内置库,PStore,它将Ruby对象转换为二进制文件并将其存储在文件中。或者,PSTORE也能够从文件中读取并将二进制返回转换为Ruby对象。序列化和反序列化是将Ruby对象融入二进制的过程,反之亦然。
但是,PSTORE以二进制文件存储文件,这些文件不可被美国人类读取。因此,我们向上移动抽象并使用Yaml :: Store,这是一个PSTORE的实现。而不是将Ruby对象序列化为二进制,Yaml :: Store序列化为人类可读的yaml文件格式。
运行Ruby Mirth-4.RB并转到LocalHost:1337 /在浏览器上显示/生日。您将看到显示与上一个运行完全相同的默认数据。
输入一些数据并重新启动应用程序。您仍然应该看到先前输入的数据! yaml文件将被更新以反映新输入。
Phew,这是很多需要的。如果有一个主题您对学习更多信息,请参阅帖子末尾的附加信息部分。
但是等待 - 我们有一个工作的Web应用程序,只用Ruby库完全写入。我们花了很多时间来到这里。我们需要了解TCP如何运行的所有低级细节,是什么使HTTP请求和响应,以及如何通过将文件存储在文件中。我的意思是......肯定有一个更好的方式来写一个Ruby Web应用程序,但如何?是的,更多的抽象!
实现TCP套接字以创建网络连接的代码通常在所有类型的Web应用程序中都相似 - 服务器创建套接字以接受客户端。在所有类型的Web应用程序中也标准化HTTP请求和响应。正如我们上面的看法,它需要很多时间和精力来重写解决HTTP的功能。 Web开发人员必须了解有关网络协议的复杂详细信息。
有机会摘要这些功能远离开发人员,他们只是试图制作Web应用程序,从而减少开销工作。我们可以使用应用程序服务器,而不是每次打开新的Web应用程序创建网络连接并编写HTTP解析逻辑并编写HTTP解析逻辑。
应用程序服务器是代表Web应用程序处理HTTP的程序,它接受和解析请求,然后生成并发送响应。就像HTTP具有其规范的情况一样,应用程序服务器也达成协议,就如何与我们的代码交谈。
机架是Ruby Application Server的规范。如果我们的Web应用程序实现了机架规范,则可以运行支持机架规范的任何应用程序服务器。您可以根据您的Web应用程序的需求使用许多应用服务器,我们将在本教程中使用Puma作为应用程序服务器。机架应用程序(或遵循机架规范的Web应用程序)是任何响应#call消息的Ruby对象,接受称为环境的哈希参数,并返回包含:的三个元素数组
它类似于HTTP消息如何看起来像,而不是字符串格式,它们是Ruby对象。
将您的Web应用程序视为一个框中,它带有HTTP请求并输出HTTP响应。机架是Web应用程序顶部的图层,可启用Puma,应用程序服务器代表Web应用程序上的HTTP请求并返回三个元素数组。
在您的应用程序应用程序应用程序中,您可以访问机架提供的更多功能。但首先,让我们看看机架应用程序如何将视图集成到我们现有的应用程序中。
通过遵循机架规范,我们将通过沿着机架规范延迟到PUMA而不是实例化我们自己的TCP插座。我们的应用程序所做的第一件事是使用提供的环境创建一个机架::请求对象。在此之后,我们不必担心接受和拆分HTTP请求的请求行我们,因为它位于请求对象中。
此代码以前是我们的案例声明,确定导致请求的端点。现在我们使用像#get这样的内置请求方法?和#path。
另一个值得注意的内置方法是#Params方法,它返回请求的正文和查询字符串解码为参数的散列。我们在帖子端点中使用它在我们从请求中获取参数,该请求是用户的输入,并将其存储在我们的yaml文件中。
如机架规范所述,我们需要返回一个由状态,标题和身体组成的三个元素数组。请注意,状态必须是整数200或更大,标题必须是哈希,并且身体必须是响应#each的对象。要使事物简单,主体对象是在此示例中的Ruby数组。
最后,我们希望务必使用机架:: parkler :: puma运行应用程序,这是运行机架应用程序的PUMA API。 PUMA继续创建TCP套接字,代表Web应用程序处理网络。
运行Ruby Mirth-5.rb。欢乐应具有与以前的运行相同的行为。请注意,在代码中替换了从机架::请求库中的方法替换了多少细节。
现在,即将使用Rack :: Request的机架应用程序,我们现在可以使用机架::响应包装HTTP响应对象。类似于Rack :: Request工作原理,我们使用机架::响应对象封装应用程序的响应逻辑。创建HTTP响应对象并准备好进行后,机架将发送应用程序的响应。
类似于如何创建Rack :: Octure对象,我们创建一个新的Rack ::响应对象来处理响应。
同样,类似于您如何询问Rack :: Request关于该请求的询问,您现在可以根据不同的端点修改响应对象以对您的喜好。例如,在GET端点中,我们将使用#write将字符串从响应的主体附加。现在将在机架::响应库中的幕后完成。
Rack ::响应也负责设置默认值。对于每个端点,您不必将状态声明为200,因为它假定200是默认代码。内容类型设置为“text / plain”。如果您希望您的回复视为不同,则可以修改它。
对于页面重定向,您现在可以使用R Ack ::响应的#write方法来设置重定向的状态和要重定向的路径。以前在两行代码中完成了什么。
一旦完成每个单个端点修改响应对象,您可以调用#finish才能通过puma发送响应。
1.运行Ruby Mirth-6.RB。请注意代码看起来的大多数手动变量分配有多么不同,以确保正确的HTTP响应现在消失并由R Ack :: response库进行了处理。
显然,将我们的数据存储在Yaml文件中并不具有更多的请求。此外,一旦您的应用程序必须存储更复杂的数据模型,yaml文件存储就会出现问题。数百万数据
......