From c68c1646ad511ad18c347fa160d0ac4d24e73c8d Mon Sep 17 00:00:00 2001 From: xiemengjun Date: Sat, 13 Oct 2012 10:19:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B8=80=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8.3.md | 44 ++++++++++++++++++++++++++++++-------------- 8.4.md | 20 ++++++++++---------- 8.5.md | 2 +- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/8.3.md b/8.3.md index a7b2b17d..d396b762 100644 --- a/8.3.md +++ b/8.3.md @@ -1,11 +1,35 @@ #8.3 REST -RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。接下来让我们来了解这种架构到底是怎么样的?Go里面如何来实现RESTful。 +RESTful,是目前最为流行的一种互联网软件架构。因为它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。本小节我们将来学习它到底是一种什么样的架构?以及在Go里面如何来实现它。 ##什么是REST -REST(REpresentational State Transfer)描述了一个架构样式的网络系统,比如Web应用程序。它首次出现在 2000年Roy Thomas Fielding的博士论文中,他是HTTP规范的主要编写者之一。REST指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。 +REST(REpresentational State Transfer)这个概念,首次出现是在 2000年Roy Thomas Fielding(他是HTTP规范的主要编写者之一)的博士论文中,它指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful的。 -Web应用程序最重要的REST原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。 +要理解什么是REST,我们需要理解下面几个概念: -在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用URI(Universal Resource Identifier)得到一个惟一的地址。所有资源都共享统一的界面,以便在客户端和服务器之间传输状态。使用的是标准的HTTP方法,比如 GET、PUT、POST 和 DELETE。 +- 资源(Resources) + + REST是"表现层状态转化",其实它省略了主语。"表现层"其实指的是"资源"的"表现层"。 + + 那么什么是资源呢?就是我们平常上网访问的一张图片、一个文档、一个视频等。这些资源我们通过URI来定位,也就是一个URI表示一个资源。 +- 表现层(Representation) + + 资源是做一个具体的实体信息,他可以有多种的展现方式。而把实体展现出来就是表现层,例如一个txt文本信息,他可以输出成html、json、xml等格式,一个图片他可以jpg、png等方式展现,这个就是表现层的意思。 + + URI确定一个资源,但是如何确定它的具体表现形式呢?应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。 + +- 状态转化(State Transfer) + + 访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,肯定涉及到数据和状态的变化。而HTTP协议是无状态的,那么这些状态肯定保存在服务器端,所以如果客户端想要通知服务器端改变数据和状态的变化,肯定要通过某种方式来通知它。 + + 客户端能通知服务器端的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。 + +综合上面的解释,我们总结一下什么是RESTful架构: + +- (1)每一个URI代表一种资源; +- (2)客户端和服务器之间,传递这种资源的某种表现层; +- (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。 + + +Web应用要满足REST最重要的原则是:客户端和服务器之间的交互在请求之间是无状态的,即从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外此请求可以由任何可用服务器回答,这十分适合云计算之类的环境。因为是无状态的,所以客户端可以缓存数据以改进性能。 另一个重要的REST原则是分层系统,这表示组件无法了解它与之交互的中间层以外的组件。通过将系统知识限制在单个层,可以限制整个系统的复杂性,促进了底层的独立性。 @@ -13,7 +37,7 @@ Web应用程序最重要的REST原则是,客户端和服务器之间的交互 ![](images/8.3.rest2.png?raw=true) -当REST架构的约束条件作为一个整体应用时,将生成一个可以扩展到大量客户端的应用程序。它还降低了客户端和服务器之间的交互延迟。统一界面简化了整个系统架构,改进了子系统之间交互的可见性。REST简化了客户端和服务器的实现。而且对于使用REST开发的应用程序更加容易扩展。 +当REST架构的约束条件作为一个整体应用时,将生成一个可以扩展到大量客户端的应用程序。它还降低了客户端和服务器之间的交互延迟。统一界面简化了整个系统架构,改进了子系统之间交互的可见性。REST简化了客户端和服务器的实现,而且对于使用REST开发的应用程序更加容易扩展。 下图展示了REST的扩展新性: @@ -74,15 +98,7 @@ Go语言对于REST没有标准包直接支持,但是因为RESTful是基于HTTP -上面的代码我们演示如何编写一个REST的应用,我们访问的资源是用户,然后我们通过不同的method来访问不同的函数,这里我们使用了一个第三方库`github.com/drone/routes`,这个库实现了方便的路由规则映射,我们在上面章节也介绍过可以实现自定义的路由器,这个库就实现了自定义的路由,我们可以很方便的实现REST的架构。通过上面的代码我们知道REST就是根据不同的method访问同一个资源的时候实现不同的逻辑处理。一般这些method的定义如下: - -- Get表示获取请求的资源信息 -- Post表示修改相应的资源信息 -- Put表示添加一个新的资源 -- Delete表示删除请求的资源信息 -- Patch表示对资源进行部分更新的一个特殊方法 - -通过上面的代码演示我们知道:资源是通过URI来确定的,然后通过不同的方式执行不同的操作方式,这就是RESTful的实现。 +上面的代码我们演示如何编写一个REST的应用,我们访问的资源是用户,然后我们通过不同的method来访问不同的函数,这里我们使用了一个第三方库`github.com/drone/routes`,这个库实现了方便的路由规则映射,我们在上面章节也介绍过可以实现自定义的路由器,这个库就实现了自定义的路由,我们可以很方便的实现REST的架构。通过上面的代码我们知道REST就是根据不同的method访问同一个资源的时候实现不同的逻辑处理。 ##总结 REST是一种架构风格,汲取了WWW的成功经验:无状态,以资源为中心,充分利用HTTP协议和URI协议,提供统一的接口定义,使得它作为一种设计Web服务的方法而变得流行。在某种意义上,通过强调URI和HTTP等早期Internet标准,REST是对大型应用程序服务器时代之前的Web方式的回归。目前Go对于REST的支持还是很简单的,通过实现自定义的路由规则,我们就可以实现不同的method实现不同的handle,这样就实现了REST的架构。 diff --git a/8.4.md b/8.4.md index 31dca74c..5c292b11 100644 --- a/8.4.md +++ b/8.4.md @@ -1,9 +1,9 @@ #8.4 RPC -前面几个小节我们介绍了基于Socket和HTTP来编写应用,通过介绍我们了解了Socket和HTTP使用类似消息传递的模式,客户端发送一个消息到服务端,然后一般服务器端都会有一定的返回信息。客户端和服务端都需要约定交互的消息格式,双方都需要对这种消息能够解析。但是很多独立的应用不会使用这种消息传递的模式,而是采用类似函数调用的方式,这种方式应用通过调用带有一串参数的函数,然后返回一组值。 +前面几个小节我们介绍了如何基于Socket和HTTP来编写网络应用,通过学习我们了解了Socket和HTTP采用的是类似"信息交换"模式,即客户端发送一条信息到服务端,然后(一般来说)服务器端都会返回一定的信息以表示响应。客户端和服务端之间约定了交互信息的格式,以便双方都能够解析交互所产生的信息。但是很多独立的应用并没有采用这种模式,而是采用类似常规的函数调用的方式来完成想要的功能。 RPC就是想实现函数调用模式的网络化。客户端就像调用本地函数一样,然后客户端把这些参数打包之后通过网络传递到服务端,服务端解包到处理过程中执行,然后执行的结果反馈给客户端。 -RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。 +RPC(Remote Procedure Call Protocol)——远程过程调用协议,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。它假定某些传输协议的存在,如TCP或UDP,以便为通信程序之间携带信息数据。通过它可以使函数调用模式网络化。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。 ##RPC工作原理 @@ -23,7 +23,7 @@ RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是 - 10.客户接收句柄返回的数据 ##Go RPC -Go标准包里面已经支持了RPC,而且支持三个级别的RPC:TCP、HTTP、JSONRPC。但Go的RPC包是独一无二的RPC,他和传统的RPC系统不一样,Go的客户端只能和Go的服务端交互,因为他们的交互采用了Go的Gob编码。 +Go标准包中已经提供了对RPC的支持,而且支持三个级别的RPC:TCP、HTTP、JSONRPC。但Go的RPC包是独一无二的RPC,它和传统的RPC系统不同,它只支持Go开发的服务器与客户端之间的交互,因为在内部,它们采用了Gob来编码。 Go RPC的函数只有符合下面的条件才能被远程访问,不然会被忽略,详细的要求如下: @@ -88,7 +88,7 @@ http的服务端代码实现如下: } } -通过上面的例子我们看到我们注册了一个Arith的RPC服务,然后通过`rpc.HandleHTTP`函数把该服务注册到了HTTP协议上,然后我们就可以利用http的方式来传递数据了。 +通过上面的例子可以看到,我们注册了一个Arith的RPC服务,然后通过`rpc.HandleHTTP`函数把该服务注册到了HTTP协议上,然后我们就可以利用http的方式来传递数据了。 请看下面的客户端代码: @@ -144,7 +144,7 @@ http的服务端代码实现如下: Arith: 17*8=136 Arith: 17/8=2 remainder 1 -通过上面的调用我们看到参数和返回值是我们定义的结构体,在服务端我们把他们当做调用函数的参数类型,在客户端作为`client.Call`的参数。客户端最重要的就是这个`Call`函数,他三个参数,第一个参数是调用对象的函数,第二个参数是传递的参数,第三个参数是返回的参数(注意是指针类型),通过上面服务端和客户端的代码例子我们发现,写Go的RPC相当的简单,调用也很方便。 +通过上面的调用可以看到参数和返回值是我们定义的struct类型,在服务端我们把它们当做调用函数的参数的类型,在客户端作为`client.Call`的第2,3两个参数的类型。客户端最重要的就是这个Call函数,它有3个参数,第1个要调用的函数的名字,第2个是要传递的参数,第3个要返回的参数(注意是指针类型),通过上面的代码例子我们可以发现,使用Go的RPC实现相当的简单,方便。 ###TCP RPC 上面我们实现了基于HTTP协议的RPC,接下来我们要实现基于TCP协议的RPC,服务端的实现代码如下所示: @@ -210,9 +210,9 @@ http的服务端代码实现如下: } } -上面这个代码和http的服务器对比,唯一不同的就是这边是采用了TCP,然后需要自己控制连接,这个连接通知给rpc来处理。 +上面这个代码和http的服务器相比,不同在于:在此处我们采用了TCP协议,然后需要自己控制连接,当有客户端连接上来后,我们需要把这个连接交给rpc来处理。 -而且我们可以发现这是一个阻塞型的单用户的程序,如果想要实现多并发,那么可以使用goroutine来实现,我们前面在socket小节的时候已经介绍过如何处理goroutine。 +如果你留心了,你会发现这它是一个阻塞型的单用户的程序,如果想要实现多并发,那么可以使用goroutine来实现,我们前面在socket小节的时候已经介绍过如何处理goroutine。 下面展现了TCP实现的RPC客户端: package main @@ -264,7 +264,7 @@ http的服务端代码实现如下: 这个客户端代码和http的客户端代码对比,唯一的区别一个是DialHTTP,一个是Dial(tcp),其他处理一模一样。 ###JSON RPC -JSON RPC是数据编码采用了JSON,而不是gob编码,其他和上面介绍的RPC概念一模一样,下面我们来看Go标准包里面如何实现JSON RPC,请看服务端代码的实现: +JSON RPC是数据编码采用了JSON,而不是gob编码,其他和上面介绍的RPC概念一模一样,下面我们来演示一下,如何使用Go提供的json-rpc标准包,请看服务端代码的实现: package main @@ -329,7 +329,7 @@ JSON RPC是数据编码采用了JSON,而不是gob编码,其他和上面介 } } -我们可以发现上面的代码是基于TCP协议的,目前只支持基于TCP协议的方式,不支持HTTP方式。 +通过示例我们可以看出 json-rpc是基于TCP协议实现的,目前它还不支持HTTP方式。 请看客户端的实现代码: @@ -380,7 +380,7 @@ JSON RPC是数据编码采用了JSON,而不是gob编码,其他和上面介 } ##总结 -Go的标准包已经对RPC支持的非常好,这样就可以开发很多分布式的Web应用,通过上面HTTP、TCP、JSON RPC的实现,我们可以领会到这一点。但唯一遗憾的是目前Go标准包里面不支持SOAP RPC协议,当然第三方开源包有在实现类似的东西,我们也可以找到相应的开源代码。 +Go已经提供了对RPC的良好支持,通过上面HTTP、TCP、JSON RPC的实现,我们就可以很方便的开发很多分布式的Web应用,我想作为读者的你已经领会到这一点。但遗憾的是目前Go尚未提供对SOAP RPC的支持,欣慰的是现在已经有第三方的开源实现了。 diff --git a/8.5.md b/8.5.md index b13a39cf..3611f190 100644 --- a/8.5.md +++ b/8.5.md @@ -1,5 +1,5 @@ #8.5 小结 -这一章我们介绍了目前流行的集中Web开发方式,第一小节介绍了网络编程中非常重要的Socket编程,因为现在云计算时代,网络通信是唯一的也是必要的一种方式,那么通过网络来进行数据的交流是多么的重要,Socket就是交流的公路,你只有了解了这条路的方向才能开快车。第二小节介绍了目前流行的HTML5中一个重要的特性WebSocket,通过这个可以实现服务器的主动推,可以简化以前ajax轮询的模式。第三小节介绍了REST编写模式,这也是目前很多大公司开发API的实现方式,这种模式特别适合来开发API,结合目前移动的快速发展,我觉得将来会是一个潮流。第四小节介绍了RPC的编程模式,可以实现分布式的应用过程实现。Go对于上面四种模式都很好的支持了,Go的`net`包下面基本实现了所有网络编程的函数。如果你想更加深入的了解里面是怎么实现的,可以尝试阅读这个包下面的源码。 +这一章我们介绍了目前流行的几种主要的网络应用开发方式,第一小节介绍了网络编程中的基础:Socket编程,因为现在网络正在朝云的方向快速进化,作为这一技术演进的基石的的socket知识,作为开发者的你,是必须要掌握的。第二小节介绍了正愈发流行的HTML5中一个重要的特性WebSocket,通过它,服务器可以实现主动的push消息,以简化以前ajax轮询的模式。第三小节介绍了REST编写模式,这种模式特别适合来开发网络应用API,目前移动应用的快速发展,我觉得将来会是一个潮流。第四小节介绍了Go实现的RPC相关知识,对于上面四种开发方式,Go都已经提供了良好的支持,net包及其子包,是所有涉及到网络编程的工具的所在地。如果你想更加深入的了解相关实现细节,可以尝试阅读这个包下面的源码。 ## links * [目录]() * 上一节: [RPC](<8.4.md>)