[转]Rest API 概念及开发简介

概述php

REST 从资源的角度来观察整个网络,分布在各处的资源由URI肯定,而客户端的应用经过URI来获取资源的表示方式。得到这些表徵导致这些应用程序转变了其状态。随着不断获取资源的表示方式,客户端应用不断地在转变着其状态,所谓表述性状态转移(Representational State Transfer)。html

这一观点不是凭空臆造的,而是经过观察当前Web互联网的运做方式而抽象出来的。Roy Fielding 认为,前端

“设计良好的网络应用表现为一系列的网页,这些网页能够看做的虚拟的状态机,用户选择这些连接致使下一网页传输到用户端展示给使用的人,而这正表明了状态的转变。”java

REST是设计风格而不是标准。REST一般基于使用HTTP,URI,和XML以及HTML这些现有的普遍流行的协议和标准。web

  • 资源是由URI来指定。
  • 对资源的操做包括获取、建立、修改和删除资源,这些操做正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。
  • 经过操做资源的表现形式来操做资源。
  • 资源的表现形式则是XML或者HTML,取决于读者是机器仍是人,是消费web服务的客户软件仍是web浏览器。固然也能够是任何其余的格式。
REST的要求
  • 客户端和服务器结构
  • 链接协议具备无状态性
  • 可以利用Cache机制增进性能
  • 层次化的系统
  • 隨需代碼 - Javascript (可選)

 

RESTful Web 服务spring

RESTful Web 服务(也称为 RESTful Web API)是一个使用HTTP并遵循REST原则的Web服务。它从如下三个方面资源进行定义:URI,好比:http://example.com/resources/。json

§ Web服务接受与返回的互联网媒体类型,好比:JSON,XML ,YAML 等。设计模式

§ Web服务在该资源上所支持的一系列请求方法(好比:POST,GET,PUT或DELETE)。浏览器

该表列出了在实现RESTful Web 服务时HTTP请求方法的典型用途。缓存

HTTP 请求方法在RESTful Web 服务中的典型应用

 

资源

GET

PUT

POST

DELETE

一组资源的URI,好比http://example.com/resources/

列出 URI,以及该资源组中每一个资源的详细信息(后者可选)。

使用给定的一组资源替换当前整组资源。

在本组资源中建立/追加一个新的资源。 该操做每每返回新资源的URL。

删除 整组资源。

单个资源的URI,好比http://example.com/resources/142

获取 指定的资源的详细信息,格式能够自选一个合适的网络媒体类型(好比:XML、JSON等)

替换/建立 指定的资源。并将其追加到相应的资源组中。

把指定的资源当作一个资源组,并在其下建立/追加一个新的元素,使其隶属于当前资源。

删除 指定的元素。

 

PUT 和 DELETE 方法是幂等方法。GET方法是安全方法 (不会对服务器端有修改,所以也是幂等的)。

不像基于SOAP的Web服务,RESTful Web服务并无的“正式”标准。 这是由于REST是一种架构,而SOAP只是一个协议。虽然REST不是一个标准,但在实现RESTful Web服务时可使用其余各类标准(好比HTTP,URL,XML,PNG等)。

REST的优势

  • 能够利用缓存Cache来提升响应速度
  • 通信自己的无状态性可让不一样的服务器的处理一系列请求中的不一样请求,提升服务器的扩展性
  • 浏览器便可做为客户端,简化软件需求
  • 相对于其余叠加在HTTP协议之上的机制,REST的软件依赖性更小
  • 不须要额外的资源发现机制
  • 在软件技术演进中的长期的兼容性更好

 

Rest 开发

首先先定义接口IRestHandler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/// <summary>
/// The IRestHandler is an interface which provides Delete,Get,Post and Put methods.
/// </summary>
public  interface  IRestHandler : ICloneable
{
     /// <summary>
     /// Delete method for RestHandler
     /// </summary>
     /// <param name="processor">The rest processor.</param>
     /// <param name="authenticated">if set to <c>true</c> [authenticated].</param>
     /// <returns>The http response</returns>
     RestHandlerResponse Delete(IRestProcessor processor, bool  authenticated);
 
     /// <summary>
     /// Get method for RestHandler
     /// </summary>
     /// <param name="processor">The rest processor.</param>
     /// <param name="authenticated">if set to <c>true</c> [authenticated].</param>
     /// <returns>The http response</returns>
     RestHandlerResponse Get(IRestProcessor processor, bool  authenticated);
 
     /// <summary>
     /// Post method for RestHandler
     /// </summary>
     /// <param name="processor">The rest processor.</param>
     /// <param name="authenticated">if set to <c>true</c> [authenticated].</param>
     /// <returns>The http response</returns>
     RestHandlerResponse Post(IRestProcessor processor, bool  authenticated);
 
     /// <summary>
     /// Put method for RestHandler
     /// </summary>
     /// <param name="processor">The rest processor.</param>
     /// <param name="authenticated">if set to <c>true</c> [authenticated].</param>
     /// <returns>The http response</returns>
     RestHandlerResponse Put(IRestProcessor processor, bool  authenticated);
}

咱们要定义一个HttpListener,先定义一个接口IRestListener:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/// <summary>
/// Listen an ip point and accept connection.
/// </summary>
public  interface  IRestListener : IDisposable
{
     /// <summary>
     /// Gets or sets the max allowed connections to this listener.
     /// </summary>
     int  MaxConnections { get ; set ; }
 
     /// <summary>
     /// Gets or sets desktop rest manager.
     /// </summary>
     DesktopRestManager DesktopRestManager { get ; set ; }
 
     /// <summary>
     /// Gets a value that indicate if it is listening.
     /// </summary>
     bool  IsRunning { get ; }
 
     /// <summary>
     /// Gets or sets the server address information.
     /// </summary>
     IPEndPoint ServerAddress { get ; set ; }
 
     string  Protocol { get ; set ; }
 
     /// <summary>
     /// Start a listener.
     /// </summary>
     /// <returns>The ip end point to listen.</returns>
     bool  Start(TcpListener listener, IPEndPoint address);
 
     /// <summary>
     /// Stop the listener.
     /// </summary>
     /// <returns>True if successfully, else false.</returns>
     bool  Stop();
}

 

 

接下来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
public  class  HttpListener : IRestListener
     {
         public  HttpListener(DesktopRestManager drm)
         {
             this .desktopRestManager = drm;
             this .isRunning = false ;          
             MaxConnections = 50;
             this .serverAddress = new  IPEndPoint( new  IPAddress( new  byte [] { 127, 0, 0, 1 }), 10000);
             this .Protocol = "Http" ;          
         }
 
         #region IRestServer Members
 
         //public event ServerStatusChangedHandler ServerStatusChanged;
 
         public  DesktopRestManager DesktopRestManager
         {
             get  { return  this .desktopRestManager; }
             set  { this .desktopRestManager = value; }
         }
 
         public  bool  IsRunning
         {
             get  { return  this .isRunning; }
         }
 
         public  IPEndPoint ServerAddress
         {
             get  { return  this .serverAddress; }
             set  { this .serverAddress = value; }
         }
 
         public  int  MaxConnections
         {
             get ;
             set ;
         }
 
         public  string  Protocol
         {
             get ;
             set ;
         }
 
 
         public  bool  Start(TcpListener tcpListener, IPEndPoint address)
         {
             this .ServerAddress = address;
             this .listener = tcpListener;
             this .isRunning = true ;
             Thread th = new  Thread( new  ThreadStart( this .Listening));
             th.Start();
             return  true ;
         }
 
         public  bool  Stop()
         {
             bool  success = true ; ;
             if  ( this .isRunning == true )
             {
                 try
                 {
                     this .isRunning = false ;
                     if  (listener != null )
                     {
                         listener.Stop();
                     }
                 }
                 catch  (SocketException socketEx)
                 {
                     _traceLog.InfoFormat( "Stop http rest server: {0}" , socketEx.Message);
                     success = false ;
                 }
                 
             }
             return  success;
         }
 
         #endregion
 
         #region IDisposable Members
 
         public  void  Dispose()
         {
             this .Stop();
         }
 
         #endregion
 
         #region Private Methods
         private  void  Listening()
         {
             while  ( this .isRunning)
             {
                 TcpClient tcpClient = null ;
                 try
                 {
                     tcpClient = listener.AcceptTcpClient();
                     HttpConnection connection = new  HttpConnection(tcpClient);
                     RestProcessor rh = new  RestProcessor( this .desktopRestManager);
                     Thread processThread = new  Thread( new  ParameterizedThreadStart(req => connection.SendResponse(rh.HandleRequest(req as  RestHandlerRequest))));
                     processThread.Name = "RestManager_Http_ProcessRequest" ;
                     processThread.Start(connection.GetRequest());
                 }
                 catch  (SocketException socketEx)
                 {
                     if  ( this .isRunning)
                     {
                         _traceLog.InfoFormat( "Socket exception: {0}" , socketEx.Message);
                     }
                     else
                     {
                         _traceLog.Info( "The use stop the http listener." );
                     }
                     if  (tcpClient != null  && tcpClient.Connected)
                     {
                         tcpClient.Close();
                     }
                 }
                 catch  (System.ArgumentNullException ex)
                 {
                     _traceLog.ErrorFormat( "Error occured: {0}" , ex.Message);
                 }
                 catch  (System.OutOfMemoryException ex)
                 {
                     _traceLog.ErrorFormat( "Error occured: {0}" , ex.Message);
                 }
                 catch  (System.Threading.ThreadStateException ex)
                 {
                     _traceLog.ErrorFormat( "Error occured: {0}" , ex.Message);
                 }
                 catch  (System.InvalidOperationException ex)
                 {
                     _traceLog.ErrorFormat( "Error occured: {0}" , ex.Message);
                 }
                 catch  (ApplicationException ex)
                 {
                     _traceLog.ErrorFormat( "Error occured: {0}" , ex.Message);
                 }
             }
             this .Stop();
         }
 
         #endregion
 
         #region Private Members
         private  DesktopRestManager desktopRestManager;
         private  bool  isRunning;
         private  IPEndPoint serverAddress;
         private  TcpListener listener;
         private  static  LogManager _traceLog = new  LogManager( "RestManager-HttpListener" );
         #endregion
     }

 

 

接下来处理HandleRequest:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/// <summary>
         /// Handles an http request for an Api call.
         /// </summary>
         public  RestHandlerResponse HandleRequest(RestHandlerRequest rhr)
         {
             RestHandlerResponse res;
             // 50 Requests in maximum
             if  (! this .restProcessorSemaphore.WaitOne(0))
             {
                 
                res = new  RestHandlerResponse(503);
             }
 
             else
             {
                 try
                 {
                     // There is no need decode the url here, since the address will be decoded when it is parsed.
                     //rhr.Address = System.Web.HttpUtility.UrlDecode(rhr.Address);
 
                     res = this .process(rhr);
 
                 }
                 catch  (RestManagerException ex)
                 {
                     traceLog.ErrorFormat( "Error happened while processing request\n{1}.\nException info:\n{0}  " ,ex.Message);
                     res = new  RestHandlerResponse(500);
                 }
                 try
                 {
                     this .restProcessorSemaphore.Release();
                 }
                 catch  (System.Threading.SemaphoreFullException)
                 {
                     traceLog.ErrorFormat( "Error happened while processing Semaphore.Release" );
                 }
                 catch  (System.IO.IOException)
                 {
                     traceLog.ErrorFormat( "Error happened while processing Semaphore.Release" );
                 }
                 catch  (System.UnauthorizedAccessException)
                 {
                     traceLog.ErrorFormat( "Error happened while processing Semaphore.Release" );
                 }
             }
 
             return  res;
         }

 

 

接下来咱们写发送请求代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private  JObject MakeRequest( string  url)
{
     var  subsequentRequest = WebRequest.Create(url) as  HttpWebRequest;
     subsequentRequest.Timeout = 30000;
     subsequentRequest.Headers.Add( "Authorization" , "OAuth "  + TestToken);
     subsequentRequest.Headers.Add( "App-User" , TestUserName);
 
     WebResponse subsequentResponse;
 
     try
     {
         subsequentResponse = subsequentRequest.GetResponse();
         Stream stream = subsequentResponse.GetResponseStream();
         StreamReader sr = new  StreamReader(stream);
         string  output = sr.ReadToEnd();
         JObject jsonStr = JObject.Parse(output);
         return  jsonStr;
 
     }
     catch  (WebException ex)
     {
         if  (ex.Response != null )
         {
             HttpWebResponse errorResponse = (HttpWebResponse)ex.Response;
             StreamReader reader = new  StreamReader(errorResponse.GetResponseStream());
             string  output = reader.ReadToEnd();
             JObject jsonStr = JObject.Parse(output);
             return  jsonStr;
         }
         else
         {
             return  null ;
         }
     }
}

 

 

涉及项目的缘由,代码只能提供这么多了,仅供参考

Json的返回结果格式以下,:

1
[{ "CreatedDate" : "//Date(1299687080328+0800)//" , "Detail" : "Do Something 1" , "Title" : "Task1" },{ "CreatedDate" : "//Date(1299687080328+0800)//" , "Detail" : "Do Something 5" , "Title" : "Task5" }]

 

REST vs SOAP 
成熟度: 
SOAP虽然发展到如今已经脱离了初衷,可是对于异构环境服务发布和调用,以及厂商的支持都已经达到了较为成熟的状况。不一样平台,开发语言之间经过SOAP来交互的web service都可以较好的互通(在部分复杂和特殊的参数和返回对象解析上,协议没有做很细致的规定,致使仍是须要做部分修正)

REST国外不少大网站都发布了本身的开发API,不少都提供了SOAP和REST两种Web Service,根据调查部分网站的REST风格的使用状况要高于SOAP。可是因为REST只是一种基于Http协议实现资源操做的思想,所以各个网站的REST实现都自有一套,在后面会讲诉各个大网站的REST API的风格。也正是由于这种各自实现的状况,在性能和可用性上会大大高于SOAP发布的web service,但统一通用方面远远不及SOAP。因为这些大网站的SP每每专一于此网站的API开发,所以通用性要求不高。

因为没有相似于SOAP的权威性协议做为规范,REST实现的各类协议仅仅只能算是私有协议,固然须要遵循REST的思想,可是这样细节方面有太多没有约束的地方。REST往后的发展所走向规范也会直接影响到这部分的设计是否可以有很好的生命力。

总的来讲SOAP在成熟度上优于REST。

效率和易用性: 
       SOAP协议对于消息体和消息头都有定义,同时消息头的可扩展性为各类互联网的标准提供了扩展的基础,WS-*系列就是较为成功的规范。可是也因为SOAP因为各类需求不断扩充其自己协议的内容,致使在SOAP处理方面的性能有所降低。同时在易用性方面以及学习成本上也有所增长。

       REST被人们的重视,其实很大一方面也是由于其高效以及简洁易用的特性。这种高效一方面源于其面向资源接口设计以及操做抽象简化了开发者的不良设计,同时也最大限度的利用了Http最初的应用协议设计理念。同时,在我看来REST还有一个很吸引开发者的就是可以很好的融合当前Web2.0的不少前端技术来提升开发效率。例如不少大型网站开放的REST风格的API都会有多种返回形式,除了传统的xml做为数据承载,还有(JSON,RSS,ATOM)等形式,这对不少网站前端开发人员来讲就可以很好的mashup各类资源信息。

       所以在效率和易用性上来讲,REST更胜一筹。

安全性: 
       这点其实能够放入到成熟度中,不过在当前的互联网应用和平台开发设计过程当中,安全已经被提到了很高的高度,特别是做为外部接口给第三方调用,安全性可能会高过业务逻辑自己。

       SOAP在安全方面是经过使用XML-Security和XML-Signature两个规范组成了WS-Security来实现安全控制的,当前已经获得了各个厂商的支持,.net ,php ,java 都已经对其有了很好的支持(虽然在一些细节上仍是有不兼容的问题,可是互通基本上是能够的)。

       REST没有任何规范对于安全方面做说明,同时如今开放REST风格API的网站主要分红两种,一种是自定义了安全信息封装在消息中(其实这和SOAP没有什么区别),另一种就是靠硬件SSL来保障,可是这只可以保证点到点的安全,若是是须要多点传输的话SSL就无能为力了。安全这块其实也是一个很大的问题,今年在BEA峰会上看到有演示采用SAML2实现的网站间SSO,实际上是直接采用了XML-Security和XML-Signature,效率看起来也不是很高。将来REST规范化和通用化过程当中的安全是否也会采用这两种规范,是未知的,可是加入的越多,REST失去它高效性的优点越多。

应用设计与改造: 
       咱们的系统要么就是已经有了那些须要被发布出去的服务,要么就是刚刚设计好的服务,可是开发人员的传统设计思想让REST的形式被接受还须要一点时间。同时在资源型数据服务接口设计上来讲按照REST的思想来设计相对来讲要容易一些,而对于一些复杂的服务接口来讲,可能强要去按照REST的风格来设计会有些牵强。这一点其实能够看看各大网站的接口就能够知道,不少网站还要传入function的名称做为参数,这就明显已经违背了REST自己的设计思路。

       而SOAP自己就是面向RPC来设计的,开发人员十分容易接受,因此不存在什么适应的过程。

总的来讲,其实仍是一个老观念,适合的才是最好的 
       技术没有好坏,只有是否是合适,一种好的技术和思想被误用了,那么就会获得反效果。REST和SOAP各自都有本身的优势,同时若是在一些场景下若是去改造REST,其实就会走向SOAP(例如安全)。

       REST对于资源型服务接口来讲很合适,同时特别适合对于效率要求很高,可是对于安全要求不高的场景。而SOAP的成熟性能够给须要提供给多开发语言的,对于安全性要求较高的接口设计带来便利。因此我以为纯粹说什么设计模式将会占据主导地位没有什么意义,关键仍是看应用场景。

       同时很重要一点就是不要扭曲了REST如今不少网站都跟风去开发REST风格的接口,其实都是在学其形,不知其心,最后弄得不三不四,性能上不去,安全又保证不了,徒有一个看似象摸象样的皮囊。

 

参考文献:

http://blog.csdn.net/terryzero/article/details/6295855

http://zh.wikipedia.org/wiki/REST

 

转自:http://www.cnblogs.com/springyangwc/archive/2012/01/18/2325784.html

参见:An Introduction to ASP.NET web API

相关文章
相关标签/搜索