注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

itoedr的it学苑

记录从IT文盲学到专家的历程

 
 
 

日志

 
 

rest开发的参考案例  

2015-04-10 10:32:49|  分类: linux‘cloud |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

两种web service的比较(REST vs SOAP )
成熟度:
            SOAP(Simple Object Access Protocol),简单对象访问协议。是交换数据的一种协议规范,是一种轻量的、简单的、基于XML的协议,它被设计成在WEB上交换结构化的和固化的信息。对于异构环境服务发布和调用,以及厂商的支持都已经达到了较为成熟的情况。不同平台,开发语言之 间通过SOAP来交互的web service都能够较好的互通,但只是较好互通。

          REST国外很多大网站都会发布自己的开发API,很多还提供了SOAP和REST两种Web Service,但实际上,大部分网站的“REST风格”的使用情况要高于“SOAP协议”。但是由于REST只是一种基于Http协议实现资源操作的思想,因此各个网站 的REST实现都自有一套具体方法,形成了自己的风格。在性能和可用性上会大大高于SOAP发布的web service,但统一通用方面远远不及SOAP。

         由于没有类似于SOAP的权威性协议作为规范,REST实现的各种协议仅仅只能算是私有协议,当然需要遵循REST的思想,但是这样细节方面有太多没有约束的地方。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风格的接口,其实都是在学其形,不知其心,最后弄得不伦不类,性能上不去,安全又保证不了,徒有一个看似象摸象样的皮囊。

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的返回结果格式:


[{"CreatedDate":"//Date(1299687080328+0800)//","Detail":"Do Something 1","Title":"Task1"},{"CreatedDate":"//Date(1299687080328+0800)//","Detail":"Do Something 5","Title":"Task5"}]
  评论这张
 
阅读(139)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017