首页>>后端>>Golang->Golang实现SOAP客户端的经验总结

Golang实现SOAP客户端的经验总结

时间:2023-11-30 本站 点击:0

引言

SOAP是一种“简单”的基于XML的协议,在10多年前流行过一阵。与现在行其道的基于JSON协议的restFul API相比,SOAP无疑要笨重许多。

如果项目的开发语言是.net或者Java,那还好还,因为IDE有方便的内置功能来解析SOAP服务的WSDL文件,自动生成Client的相关代码。但如果是用Golang,那就麻烦了。

下面说说SOAP的不同之处,或者说麻烦的地方。

SOAP的不同之处

Request/Response结构复杂,嵌套层级多且深

下面是一个Request Body的示例,这个XML是必须指定特定的namespace的。API的验证密钥信息,也是要写在Request Body中。

<soapenv:Envelopexmlns:ns="http://www.id3global.com/ID3gWS/2013/04"xmlns:soap="soap"xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Headerxmlns:wsa="http://www.w3.org/2005/08/addressing"><wsse:Securitysoapenv:mustUnderstand="1"xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsse:UsernameToken><wsse:Username></wsse:Username><wsse:Password></wsse:Password></wsse:UsernameToken></wsse:Security></soapenv:Header><soapenv:Body></soapenv:Body></soapenv:Envelope>

通常soapenv:Body部分通常是会更加复杂的,如果没有工具支持,纯手工来写,累人不说,还容易出错。

Header的设置

Content-Type:text/xml;charset="utf-8"SOAPAction:http://www.id3global.com/ID3gWS/2013/04/IGlobalAuthenticate/AuthenticateSP

header中的Content-Typeapplication/json, 可不要下意识的写成application/json哦。而SOAPAction这个header就是特别注意了,需要设置成要调用的action,而且需要注意的是,不同的action的baseUrl可能是不一样的。相比而言,restFul的API可没这么多坑。

multiple part的reponse

虽说大部分时候,SOAP的返回数据是XML格式,但有时会是如下这种multiple part的格式,解析起来也是需要些功夫的。

--uuid:6d335978-5c93-40b7-b5c4-3acc067e3d8c+id=302Content-ID:<http://tempuri.org/0>Content-Transfer-Encoding:8bitContent-Type:application/xop+xml;charset=utf-8;type="text/xml"<s:Envelopexmlns:s="http://schemas.xmlsoap.org/soap/envelope/"xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><o:Securitys:mustUnderstand="1"xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"></s:Header><s:Body></s:Body></s:Envelope>--uuid:6d335978-5c93-40b7-b5c4-3acc067e3d8c+id=302--

时间的反序列化与Golang的time.Time类型

Golang的time.Time类型在unmarshal时是需要time zone的信息的,简单来说就是结尾至少要有个Z,例:2021-09-23T14:55:43.835Z。如果没有time zone信息,如:2024-07-13T00:00:00,那么,或者你不用time.Time而用string,再或者就是重写UnmarshalXML的方法了。

解决方案

写了这么多,你也会发现,如果没有现成的工具,自己要处理的细节不是一般的多。

本着技术领域没有新问题,或者说你永远不会是第一个遇到这个问题的人,我开始搜索之路,不得不说搜索还是要google!

我通过medium上的一篇文章,找到心仪的工具, gowsdl,你可以用这个工具方便的生成模板代码:

gowsdl[options]myservice.wsdl

但是呢,我不建议你直接使用生成的代码,而只是使用它定义的结构,自己再重新封装一个client,原因是:

通常一个wsdl里定义的action特别多,而你只需要用其中一两个action

再则,生成的代码关于时间字段默认使用的还是time.Time,建议还是自己手动改成gowsdl中定义好的XSDDateTime。想想也是好笑,为啥不直接用XSDDateTime呢。

总体来说,生成的代码也是有很多优点的:

可以识别出Enum,会生成特定的类型及值。

可以识别出每个action对应的SOAPAction的http header

最后,再提一点,不知道是我集成的第三方服务的SOAP协议特别古老了,还是这个库有bug,总之,是在处理multiple part的response时,有一些检查的逻辑没过,我是提了一个PR,虽说目前还没人处理,但确实有些tricky。

在这种情况,就涉及到另一个问题,在用go mod管理第三方包的时候,如何hotfix在引用包中发现的问题?

其实,主要是可以分3步:

在github上,fork一个自己的repo

改动相关代码,然后Push一个新的tag

但因为这个Module的引用名称还要保持原来的名字,如果用自己克隆的repo的,就会遇到下面这个错误:

go:github.com/ksloveyuan/gowsdl@v0.5.1:parsinggo.mod:moduledeclaresitspathas:github.com/hooklift/gowsdlbutwasrequiredas:github.com/ksloveyuan/gowsdl

我没深入调查原因,但感觉是和go.mod有关。还是那句话,你不会是第一个遇到这个问题人,解决方法是使用go.mod中的replace功能,在go.mod文件的最后,加入下面这行代码就可以修复这个错误了

replacegithub.com/hooklift/gowsdlv0.5.0=>github.com/ksloveyuan/gowsdlv0.5.1


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Golang/4536.html