restful发布服务

概述

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

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

“设计良好的网络应用表现为一系列的网页,这些网页可以看作的虚拟的状态机,用户选择这些链接导致下一网页传输到用户端展现给使用的人,而这正代表了状态的转变。”

REST是设计风格而不是标准。REST通常基于使用HTTP,URI,和XML以及HTML这些现有的广泛流行的协议和标准。

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

RESTful Web 服务

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

§ 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://www.cnblogs.com/springyangwc/archive/2012/01/18/2325784.html

时间: 2024-10-18 06:47:28

restful发布服务的相关文章

spring+cxf+hibernate&#160;&#160;发布restful&#160;WebService服务

项目目录结构 项目下载路径: http://pan.baidu.com/s/1o6H06LW   (如果项目路径实效,可以qq找我,下面有我qq) 1.we b.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.c

spring,cxf,restful发布webservice传递List,Map,List&lt;Map&gt;

上一篇文章中概述了怎么在Javaweb中发布webservice,这篇文章讲解怎么传递复杂的对象 所用的jar包如下 当服务器返回的是List或者是Map时,一定要将其封装在一个类中, 首先创建封装类,封装了List,Map对象,以及自定义的User类 User.java public class User { private String name; private int age; public User() { } public User(String name, int age) { t

[译]Spring Boot 构建一个RESTful Web服务

翻译地址:https://spring.io/guides/gs/rest-service/ 构建一个RESTful Web服务 本指南将指导您完成使用spring创建一个“hello world”RESTful Web服务的过程. 你将会构建什么 您将构建一个将接受HTTP GET请求的服务: 您将构建一个将接受HTTP GET请求的服务: http://localhost:8080/greeting 1 1 并且使用JSON的形式进行响应: {"id":1,"conten

[CI] 使用CodeIgniter框架搭建RESTful API服务

在2011年8月的时候,我写了一篇博客<使用CodeIgniter框架搭建RESTful API服务>,介绍了RESTful的设计概念,以及使用CodeIgniter框架实现RESTful API的方法.转眼两年过去了,REST在这两年里有了很大的改进.我对于前一篇博客中的某些方面不是很满意,所以希望能利用这次机会写一个更加完善的版本.我的项目基于Phil Sturgeon的CodeIgniter REST Server,遵循他自己的DBAD协议.Phil的这个项目很棒,干净利落,简单实用,并

Axis1.4之即时发布服务

下载axis1.4开发包,解压开发包,将webapps目录下的axis文件夹拷贝到tomcat的webapps目录下.启动tomcat,在浏览器输入http://localhost:8080/axis得到如下页面: 实用axis的发布服务平台,创建和发布WebService服务有两种方式:即时发布和定制发布.即时发布服务很少用,但是为了知识体系的完整性,这里还是讲一下.本篇文章只讲即时发布服务. 写一个没有包的Java类HelloWS.java: public class HelloWS{ pu

Yii2快速构建RESTful Web服务功能简介

Yii2相比Yii1而言,一个重大的改进是内置了功能完备的RESTful支持. 其内置RESTful支持提供了如下功能: 使用ActiveRecord的通用接口来快速构建原型: 应答格式协商(缺省支持 JSON 和 XML): 可定制的对象序列化,支持选择输出哪些列: 请求数据的格式化以及验证错误: 通过HTTP 动词映射实现高效路由: 支持 OPTIONS 和 HEAD 动词: 认证 和 鉴权: 支持 HATEOAS(RESTful的架构约束,超媒体即应用程序状态): 结果缓存,可使用 yii

让你的 wowza 服务器提供 RESTful web 服务

有时我们 nginx 需要和 wowza 服务器交互以进行一些 LB 事宜:有时我们的管理员需要实时了解 wowza 服务器的一些其他状态信息(比如一些自定义对象的状态等等),而用 rtmp 不是太方便.这些情况下,如果我们的 wowza 服务器能提供一个 http api 就好了,就像 web 容器 tomcat 那样.本文以一个简单的 http 发送参数到 wowza,然后 wowza 返回一个 json 为例(经典的 REST 案例),介绍如何让你的 wowza 服务器提供 RESTful

ArcGIS Server发布服务,打包成功,发布失败

打包成功,发布失败 部分解决方案: ①   查看Server对于源数据所在文件夹是否有读写权限,若无赋予Server账户至少读写权限.读写权限的赋予:对应存放数据的文件夹上右键→属性→ 安全 赋予arcgis server account(如果安装时没有改名字, 默认名字为arcgis)读写权限,如果列表中没有该账户,点 编辑→ 添加→ 输入对象名称→ 检查名称 ②   在arcmap里新建一个空白的mxd,添加一个本地的数据,如存放在本地的shapefile或file gdb里的要素类,然后发

WIN 10 IIS 服务或万维网发布服务,或者依赖这两种服务的某个服务未能启动。该服务或所依赖的服务可能在启动期间发生错误或者已禁用。

环境:win10 企业版 今天重启iis的时候报出了下面的错误: 即:IIS 服务或万维网发布服务,或者依赖这两种服务的某个服务未能启动.该服务或所依赖的服务可能在启动期间发生错误或者已禁用.在网络上搜索解决方案,比如: 即:点击打开链接 这三个服务我也禁止了: 上面的方案我在win7下操作成功了(之前win7下也遇到过这个问题),但在win 10下没有效果. 于是查看系统日志: 具体信息如下:日志名称:          System来源:            Service Control