Merging other languages

This commit is contained in:
James Miranda
2016-09-23 18:01:10 -03:00
parent 380a8ee74c
commit de3c5bdaa4
490 changed files with 24539 additions and 24588 deletions

View File

@@ -1,114 +1,123 @@
# 8.3 REST
RESTful是目前最为流行的一种互联网软件架构。因为它结构清晰、符合标准、易于理解、扩展方便所以正得到越来越多网站的采用。本小节我们将来学习它到底是一种什么样的架构以及在Go里面如何来实现它。
## 什么是REST
REST(REpresentational State Transfer)这个概念,首次出现是在 2000年Roy Thomas Fielding他是HTTP规范的主要编写者之一的博士论文中它指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful的。
要理解什么是REST我们需要理解下面几个概念:
- 资源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原则是系统分层这表示组件无法了解除了与它直接交互的层次以外的组件。通过将系统知识限制在单个层可以限制整个系统的复杂性从而促进了底层的独立性。
下图即是REST的架构图
![](images/8.3.rest2.png?raw=true)
图8.5 REST架构图
当REST架构的约束条件作为一个整体应用时将生成一个可以扩展到大量客户端的应用程序。它还降低了客户端和服务器之间的交互延迟。统一界面简化了整个系统架构改进了子系统之间交互的可见性。REST简化了客户端和服务器的实现而且对于使用REST开发的应用程序更加容易扩展。
下图展示了REST的扩展性
![](images/8.3.rest.png?raw=true)
图8.6 REST的扩展性
## RESTful的实现
Go没有为REST提供直接支持但是因为RESTful是基于HTTP协议实现的所以我们可以利用`net/http`包来自己实现当然需要针对REST做一些改造REST是根据不同的method来处理相应的资源目前已经存在的很多自称是REST的应用其实并没有真正的实现REST我暂且把这些应用根据实现的method分成几个级别请看下图
![](images/8.3.rest3.png?raw=true)
图8.7 REST的level分级
上图展示了我们目前实现REST的三个level我们在应用开发的时候也不一定全部按照RESTful的规则全部实现他的方式因为有些时候完全按照RESTful的方式未必是可行的RESTful服务充分利用每一个HTTP方法包括`DELETE``PUT`。可有时HTTP客户端只能发出`GET``POST`请求:
- HTML标准只能通过链接和表单支持`GET``POST`。在没有Ajax支持的网页浏览器中不能发出`PUT``DELETE`命令
- 有些防火墙会挡住HTTP `PUT``DELETE`请求要绕过这个限制,客户端需要把实际的`PUT``DELETE`请求通过 POST 请求穿透过来。RESTful 服务则要负责在收到的 POST 请求中找到原始的 HTTP 方法并还原。
我们现在可以通过`POST`里面增加隐藏字段`_method`这种方式可以来模拟`PUT``DELETE`等方式但是服务器端需要做转换。我现在的项目里面就按照这种方式来做的REST接口。当然Go语言里面完全按照RESTful来实现是很容易的我们通过下面的例子来说明如何实现RESTful的应用设计。
package main
import (
"fmt"
"github.com/drone/routes"
"net/http"
)
func getuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are get user %s", uid)
}
func modifyuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are modify user %s", uid)
}
func deleteuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are delete user %s", uid)
}
func adduser(w http.ResponseWriter, r *http.Request) {
uid := r.FormValue("uid")
fmt.Fprint(w, "you are add user %s", uid)
}
func main() {
mux := routes.New()
mux.Get("/user/:uid", getuser)
mux.Post("/user/", adduser)
mux.Del("/user/:uid", deleteuser)
mux.Put("/user/:uid", modifyuser)
http.Handle("/", mux)
http.ListenAndServe(":8088", nil)
}
上面的代码演示了如何编写一个REST的应用我们访问的资源是用户我们通过不同的method来访问不同的函数这里使用了第三方库`github.com/drone/routes`在前面章节我们介绍过如何实现自定义的路由器这个库实现了自定义路由和方便的路由规则映射通过它我们可以很方便的实现REST的架构。通过上面的代码可知REST就是根据不同的method访问同一个资源的时候实现不同的逻辑处理。
## 总结
REST是一种架构风格汲取了WWW的成功经验无状态以资源为中心充分利用HTTP协议和URI协议提供统一的接口定义使得它作为一种设计Web服务的方法而变得流行。在某种意义上通过强调URI和HTTP等早期Internet标准REST是对大型应用程序服务器时代之前的Web方式的回归。目前Go对于REST的支持还是很简单的通过实现自定义的路由规则我们就可以为不同的method实现不同的handle这样就实现了REST的架构。
## links
* [目录](<preface.md>)
* 上一节: [WebSocket](<08.2.md>)
* 下一节: [RPC](<08.4.md>)
# 8.3 REST
REST is the most popular software architecture on the internet today because it is founded on well defined, strict standards and it's easy to understand and expand. mOre and more websites are basing their designs on to top of it. In this section, we are going to have a close look at implementing the REST architecture in Go and (hopefully) learn how to leverage it to our benefit.
## What is REST?
The first declaration of the concept of REST (REpresentational State Transfer) was in the year 2000 in Roy Thomas Fielding's doctoral dissertation, who is also just happens to be the co-founder of the HTTP protocol. It specifies the architecture's constraints and principles and anything implemented with architecture can be called a RESTful system.
Before we understand what REST is, we need to cover the following concepts:
- Resources
REST is the Presentation Layer State Transfer, where the presentation layer is actually the resource presentation layer.
So what are resources? Pictures, documents or videos, etc., are all examples of resources and can be located by URI.
- Representation
Resources are specific information entities that can be shown in a variety of ways within the presentation layer. For instance, a TXT document can be represented as HTML, JSON, XML, etc; an image can be represented as jpg, png, etc.
URIs are used to identify resources, but how do we determine its specific manifestations? You should the Accept and Content-Type in an HTTP request header; these two fields describe the presentation layer.
- State Transfer
An interactive process is initiated between client and server each time you visit any page of a website. During this process, certain data related to the current page state need to be saved. However, you'll recall that HTTP is a stateless protocol! It's obvious that we need to save this client state on our server side. It follows that if a client modifies some data and wants to persist the changes, there must be a way to inform the server side about the new state.
Most of the time, clients inform servers of state changes using HTTP. They have four operations with which to do this:
-GET is used to obtain resources
-POSTs is used to create or update resources
-PUT updates resources
-DELETE deletes resources
To summarize the above:
- 1Every URI reresents a resource.
- 2There is a representation layer for transferring resources between clients and servers.
- 3Clients use four HTTP methods to implement "Presentation Layer State Transfer", allowing them to operate on remote resources.
The most important principle of web applications that implement REST is that the interaction between clients and servers are stateless; every request should encapsulate all of the required information. Servers should be able to restart at anytime without the clients being notified. In addition, requests can be responded by any server of the same service, which is ideal for cloud computing. Lastly, because it's stateless, clients can cache data for improving performance.
Another important principle of REST is system delamination, which means that components in one layer have no way of interacting directly with components in other layers. This can limit system complexity and encourage independence in the underlying components.
![](images/8.3.rest2.png?raw=true)
Figure 8.5 REST architecture
When RESTful constraints are judiciously abided by, web applications can be scaled to accommodate massive numbers of clients. Using the REST architecture can also help reduce delays between clients and servers, simplify system architecture and improve the visibility of sub-system end points.
![](images/8.3.rest.png?raw=true)
Figure 8.6 REST's expansibility.
## RESTful implementation
Go doesn't have direct support for REST, but since RESTful web applications are all HTTP-based, we can use the `net/http` package to implement it on our own. Of course, we will first need to make some modifications before we are able to fully implement REST.
REST uses different methods to handle resources, depending on the interaction that's required with that resource. Many existing applications claim to be RESTful but they do not actually implement REST. I'm going to categorize these applications into several levels depends on which HTTP methods they implement.
![](images/8.3.rest3.png?raw=true)
Figure 8.7 REST's level.
The picture above shows three levels that are currently implemented in REST. You may not choose to follow all the rules and constraints of REST when developping your own applications because sometimes its rules are not a good fit for all situations. RESTful web applications use every single HTTP method including `DELETE` and `PUT`, but in many cases, HTTP clients can only send `GET` and `POST` requests.
- HTML standard allows clients send `GET` and `POST` requests through links and forms. It's not possible to send `PUT` or `DELETE` requests without AJAX support.
- Some firewalls intercept `PUT` and `DELETE` requests and clients have to use POST in order to implement them. Fully RESTful services are in charge of finding the original HTTP methods and restoring them.
We can simulate `PUT` and `DELETE` requests by adding a hidden `_method` field in our POST requests, however these requests must be converted on the server side before they are processed. My personal applications use this workflow to implement REST interfaces. Standard RESTful interfaces are easily implemented in Go, as the following example demonstrates:
package main
import (
"fmt"
"github.com/drone/routes"
"net/http"
)
func getuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are get user %s", uid)
}
func modifyuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are modify user %s", uid)
}
func deleteuser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprintf(w, "you are delete user %s", uid)
}
func adduser(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
uid := params.Get(":uid")
fmt.Fprint(w, "you are add user %s", uid)
}
func main() {
mux := routes.New()
mux.Get("/user/:uid", getuser)
mux.Post("/user/:uid", modifyuser)
mux.Del("/user/:uid", deleteuser)
mux.Put("/user/", adduser)
http.Handle("/", mux)
http.ListenAndServe(":8088", nil)
}
This sample code shows you how to write a very basic REST application. Our resources are users, and we use different functions for different methods. Here, we imported a third-party package called `github.com/drone/routes`. We've already covered how to implement a custom router in previous chapters -the `drone/routes` package implements some very convenient router mapping rules that make it very convenient for implementing RESTful architecture. As you can see, REST requires you to implement different logic for different HTTP methods of the same resource.
## Summary
REST is a style of web architecture, building on past successful experiences with WWW: statelessness, resource-centric, full use of HTTP and URI protocols and the provision of unified interfaces. These superior design considerations has allowed REST to become the most popular web services standard. In a sense, by emphasizing the URI and leveraging early Internet standards such as HTTP, REST has paved the way for large and scalable web applications. Currently, the support that Go has For REST is still very basic. However, by implementing custom routing rules and different request handlers for each type of HTTP request, we can achieve RESTful architecture in our Go webapps.
## Links
- [Directory](preface.md)
- Previous section: [WebSocket](08.2.md)
- Next section: [RPC](08.4.md)