使用WSDL生成REST客户端是否不正确?

3 投票
5 回答
3592 浏览
提问于 2025-04-15 19:36

我想创建一个相对简单的网络服务,用于公司内部使用。这个服务最终会成为一个数据库的接口,帮助我跟踪公司内部各种工具的运行情况。我希望这个网络服务能让公司内部的不同工具(用不同的编程语言)轻松地更新数据库,而不需要了解数据库的结构。

我已经看过很多关于REST和SOAP的问题,但我还是不太确定自己该怎么选择。

我的困惑在于,我想要REST的简单性,同时又希望有WSDL那种代码生成的能力,这似乎意味着我得用SOAP。我非常希望公司内部的各种工具(比如JAVA、Perl、Python、PHP、C++)都能和这个服务进行沟通。如果每种语言都要手动重写和维护接口层,那就太麻烦了,而用WSDL可以帮我自动处理这些。根据我的理解,如果网络服务需要更改,只需更新WSDL,重新生成客户端代码,然后对使用这些代码的部分进行必要的修改(这本来就得做)。

举个例子,假设我有一个用JAVA写的工具,它使用了一个RESTful网络服务。我想这个工具会有特定的代码来处理某些网址,发起请求,处理响应,把响应转化为我想要的数据结构等等。现在假设我还有一个用Perl写的工具,也做同样的事情。那我就需要写Perl代码来处理同样的事情,发请求、获取响应、处理这些响应等等。在每种情况下,包括C++、Python和C#,因为代码不能共享,最终我都会得到一些封装类或方法,来隐藏这些复杂的细节。我更希望能调用一个类中的函数,返回一个封装好的对象,而不是担心网址、参数、响应等问题。虽然在某个地方的代码可能不多,但时间长了就会累积起来。把这些工具都考虑进去,当我对服务进行更改时,就必须在每个CRUD操作中更新网址和相关内容。我想用WSDL的话,这些事情就能自动处理。我的代码只需和生成的代码交互,生成的代码做什么无所谓。网址、参数、响应,如果有任何变化,只需从WSDL重新生成代码。如果这个过程导致我的代码出错,那也没关系,至少我不需要更新所有处理请求和响应细节的代码。这真的是个问题吗?也许我需要做的就是创建一个服务和几个客户端,看看实际情况如何。

虽然我在JAVA、Perl、Python、C++等方面有一定的编程经验,但这是我第一次考虑创建一个网络服务,也没有其他网络服务的经验,所以我希望能得到一些指导。我是应该选择WSDL/SOAP,还是忽略大家说的REST那么流行、简单和有用的说法呢?

5 个回答

1

你提到的代码生成这个功能,虽然很重要,但我觉得它的实际价值值得怀疑。

无论是通过WSDL文档,还是你自己为REST风格的实现写的文档,客户都必须遵循你发布的接口。WS/SOAP(代码生成)开发模式可能有更多的工具,但我认为那是因为它比较笨重,所以需要这些工具来帮助。

你的网络服务的“可集成性”并没有受到影响。这其实是关于发布正式接口的问题(无论它是什么形式)。而且,从接口变更到实现变更的速度,在REST风格的服务中可能更快。启动(并且与之斗争)WS-*代码生成工具是需要时间的。

1

Fossill,

我建议你不要费心去学习SOAP。Ws-*的学习曲线非常陡峭,而且它的复杂性其实是多余的,可能会让你感到很痛苦。

根据你的技能(Java、Perl、Python、C++),你应该会对使用REST(或者至少是基于HTTP的方法)感到很满意。而且:你会很快看到结果。

正如S.Lott所说,不用担心代码生成。你根本不需要它。

如果有问题,我建议你加入Yahoo小组的rest-discuss: http://tech.groups.yahoo.com/group/rest-discuss/ 在那儿,你通常能很快得到关于REST的帮助。

就我个人而言,我还没有看到任何使用WS-*的场景会有好处。

Jan

5

我不太明白这里的代码生成问题。

其实,REST很少需要什么代码生成。它就是通过HTTP请求发送简单的JSON(或XML)数据。

你可以使用现有的HTTP库(比如Apache Commons或Python的urllib2)。也可以用现有的JSON(或XML)库。(例如,Jersey项目有一个不错的JAXB-JSON转换功能)。

那么“生成”的是什么呢?我们在Java和Python中的RESTful库几乎是一样的,只是通过HTTP库发出REST请求。

class OurService {
    def getAResource( String argValue ) {
        path = { "fixed", argValue };
        URI uri= build_path( path );
        return connection.get( uri )

[我省略了异常处理的部分。]

你是在尝试把复杂的SOAP接口/实现分离加进来吗?


一个“用JAVA写的客户端,利用RESTful网络服务”……一个“用Perl做同样事情的工具”……“用C++、Python和C#”。

没错。

“代码无法共享”

没错,代码确实无法共享。你必须用合适的语言为每个客户端写代码。写一个“生成器”从WSDL生成这些代码是(1)工作量巨大,且(2)没有必要。每种语言都有独特的语法和库来发出REST请求。但其实这很简单,几乎没有什么复杂的东西。

在Python中的经典例子是

class Some_REST_Stub( object ):
    def get_some_resource( self, arg ): # This name is from the WSDL
        uri = "http://host:port/path/to/resource/%s/" % arg # This path is from the WSDL
        data= urllib2.open( uri )
        return json.load( data )

这段代码比描述它所需的WSDL还要。而且看起来更容易修改,因为方法名就是名称,URI只是一个字符串。

在大多数语言中,客户端大致上也这么简单。我刚在Java中写了一堆REST客户端代码。虽然字数多一些,但都是一些通用的东西。构建请求,解析返回的JSON。就这样。

一个RESTful的WSDL声明在很多XML中埋藏了两条简单的信息。

  • 它为URI提供了一个“接口名称”。

  • 它通过提供Stub类的方法名来说明GET、PUT、POST和DELETE的含义。

这并没有帮助你写很多代码,因为代码本身就不多。注意,所有REST请求都有相同的通用HttpRequest和HttpResponse结构。请求包含通用的实体,响应也包含一个需要解析的通用实体。REST的内容非常少——重点就是尽可能简单。

这在很大程度上消除了对WSDL的需求,因为一切都是通用的JSONObject或XML URLEncoded,并作为字符串发送。

“我更希望调用一个返回封装在对象中的数据的类的方法,而不是担心URL、参数、响应等等。”

没错,你需要写一个“stub”类。它几乎没有代码,而且会比描述它所需的WSDL短。

“如果我在每个工具上都这样做,那么当我对服务进行更改时,我必须更新每个CRUD操作中的URL以及所有相关内容。”

你可以在每种语言中为每个客户端更新stub类。或者你可以更新WSDL,然后重新生成每个客户端。看起来工作量差不多,因为URI在客户端代码中是很简单的。

“我想象中,WSDL就是为你完成的那个部分。”

我不太明白“完成”是什么意思。是把冗长复杂的WSDL翻译成简单的stub类吗?我想这可能有帮助。可WSDL的内容比stub类要多。我建议你会发现直接写stub类更容易。它比WSDL短。

“你的代码只是与stubs交互。”

没错。

“stubs做什么,谁在乎?URL、参数、响应——如果有什么变化,只需从WSDL重新生成stubs。”

可惜,几乎没有这些需要真正编程的内容。从WSDL生成代码的工作量比直接写代码还要多。URI是字符串,参数是通用的JSONObjects,响应是包括JSONArray的通用HttpResponses。就这样。

“我不需要更新所有处理请求和响应细节的代码。”

不过,实际上,处理请求并没有什么有趣的细节。HTTP是简单的通用内容。GET、POST、PUT和DELETE几乎都是一样的。

撰写回答