ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PowerBuilder调用WebService全流程指南:从代理生成到生产环境踩坑

PowerBuilder调用WebService全流程指南:从代理生成到生产环境踩坑 简介面向PB开发人员的精简技术资源围绕在PB中如何调用WebService这一常见集成需求提供一个完整的WSDL示例文件。WSDL作为Web服务的接口描述契约定义了服务端点、操作方法、输入输出消息格式是理解PB中“添加Web引用”、自动生成代理类并完成远程调用的关键。资源包为RAR压缩格式内含1个xml文件包体仅626B麻雀虽小但便于直接查看和对比学习。目前已吸引269人学习适合正在接触PB与外部系统对接、需要快速掌握SOAP与XML调用方式的初中级开发者。通过研读该WSDL文件能够直观了解服务定义的组成元素并在此基础上进行模拟调用、验证代码逻辑或扩展出自己的代理类从而少走弯路。 先说一句防误会这里的PB是PowerBuilder不是炒股软件里那个市净率PB也不是Photoshop批处理。我为什么要强调这个因为我去搜“PB调用WebService”的时候居然翻出来一堆讲Python加载pb格式模型、讲PE/PB/PS估值口径的文章技术社区的信息污染已经到了夸张的程度。这篇就是写给还在维护PowerBuilder老系统的人看的把从零到一的调用流程、代码骨架、生产环境踩坑全部过一遍。这些年银行、电力、制造企业的系统里PowerBuilder 9、11.5甚至12的老项目还在稳定跑着前端是PB写的窗体数据窗口一屏一屏展示业务数据而后端早就换成了Java、C#或Python的服务。两边要打通最常见的手段就是WebService。PB从9.0开始就内置SOAP客户端能力通过SoapConnection对象加一个代理类把远程WebService当成本地方法一样调用传参、返回值、异常处理套路和当年调本地函数差不多。这篇文章会完整走一遍先讲清楚PB调用WebService的底层机制和适配场景再讲代理类生成和项目引用接着贴同步/异步调用的代码骨架然后把我实际生产环境里踩过的超时、证书、中文乱码、本地WSDL这些坑一个个拆开讲最后附一份错误排查思路。适合刚接手PB老项目、需要做接口对接的开发者也适合被运维喊去处理“调用服务老失败”的同学。1. 先把前提说清楚PB调用WebService到底动了什么1.1 什么场景该用WebService什么场景别硬凑PB是老牌C/S开发工具客户端装在各业务电脑上直接连数据库。但今天很少有系统能独立存活客户要对接ERP、电商平台、短信网关、统一认证中心不可能让每个客户端直连对方的数据库这时候WebService就派上用场。WebService解决的核心问题是跨语言、跨平台、跨网络。服务端用Java、C#、Python都无所谓只要暴露WSDLPB就能通过SOAP协议访问。早几年我见过不少PB写的订单下载、库存同步工具对接的就是电商开放平台底层逻辑无非是拼SOAP请求调接口这活儿PB完全能干。但也要泼盆冷水如果调用频率高、数据量大、对延迟敏感比如每分钟同步几千条明细SOAP的XML序列化和HTTP开销会让你很难受。这种场景优先考虑消息队列、批量文件接口或让服务端提供REST接口用PB的HttpClient来调。技术选型不是越时髦越好适合业务场景才重要。1.2 版本差异与运行时环境PB从9.0开始支持WebService客户端但不同版本的实现和依赖差异不小我整理了一张表供参考PB版本SOAP客户端支持情况部署注意事项PB 9.0 / 10支持SoapConnection必须带pbsoapclient90.dll/100.dllPB 11.5支持引入.NET互操作需要.NET Framework 2.0以上PB 12.xSoapConnection成熟部署环境建议装.NET Framework 4.xPB 2017及以上支持超时、证书校验设置依赖.NET Framework可调参数更多很多老系统环境里就一个pbvm.dll、pbdwe.dll其他运行时都没装全。调WebService报错后第一反应不是代码问题而是去安装目录找找有没有对应版本的SOAP客户端运行库文件名一般是pbsoapclient加版本号后缀。找不到就先补DLL别急着改代码。1.3 WSDL文件与代理类PB的翻译官WSDL可以理解成服务的说明书里面有服务地址、方法名、参数类型、返回值结构。PB拿到WSDL后干什么生成本地代理类这个代理类就是翻译官把你的PowerScript方法调用翻译成SOAP请求再把服务端返回的SOAP响应翻回PowerScript类型。有个细节新手经常懵生成代理的时候明明已经填过WSDL地址了为什么写代码时CreateInstance还要再传一次WSDL和PortName因为代理类只负责提供方法定义和参数结构真正发起网络请求时SoapConnection还是要现场读一遍WSDL才知道服务地址、命名空间、绑定协议。所以这两个参数一个都不能少且要保证运行时能访问到WSDL。2. WebService代理生成与项目引用的关键操作2.1 用PB IDE自带向导生成代理不同版本的向导入口略有差异但逻辑一致。这里以常见版本为例先确认WSDL地址能访问用浏览器打开能看到一段XML而不是404或登录页。在PB中选择File - New找到Web Service Proxy向导。填入WSDL的URL也可以选本地文件路径。选择保存代理对象的PBL库。点完成后PB自动生成代理对象通常以n_开头方法名对应WSDL里定义的operation。生成完别急着写代码先打开代理对象看一眼生成的方法签名。比如WSDL里有个方法叫queryUser(string userId)代理里可能长成of_queryUser或直接保留原名参数类型也会被映射成PB的string、long、date等。记住这个方法名后面调用全靠它。2.2 生成之后立刻检查三件事第一件事确认PortName。一个WSDL里可能有多个port每个port对应不同的服务地址或协议绑定。打开WSDL文件搜索wsdl:service标签里面会列出port名称和location地址。记下你要用的那个纯文本名称后面CreateInstance要用。第二件事检查命名冲突。有些Java或C#接口喜欢重载方法比如getUser(string)和getUser(int)但PB的代理类不支持方法重载向导可能会报错或给方法改名。遇到这种WSDL需要手动调整代理类方法名或者让服务端修改接口否则没法用。第三件事看复杂类型映射。WSDL里的复杂类型PB会生成对应的结构体类或自定义类。如果服务端返回的是一个对象数组PB侧生成的可能是一个数组遍历时要注意下标从1开始这是PB老规矩了。2.3 把代理用进项目并正确发布代理生成到某个PBL后确保这个PBL在应用的库搜索路径里。发布的时候如果编译成PBD那么包含代理类的PBD必须和主程序一起分发缺了它客户端一启动就找不到对象。服务端接口升级了怎么办不用重新发布整个客户端只需拿新WSDL重新生成代理替换原有PBD或DLL就可以。这一点在维护老系统时特别省心也是很多项目即使嫌弃SOAP重也硬着头皮用的原因。我的习惯是把每次对接用的WSDL和XSD文件放在源码库的soapdef目录里和版本一起管理。这样接口升级了能一眼看出改了什么不至于项目交接后没人说得清当时对接的是哪个版本的服务。3. 同步调用与异步调用代码怎么写才顺手3.1 同步调用的完整代码骨架直接给一份能跑的骨架以调用一个queryUser方法为例soapconnection lsc_conn n_ws_userquery lsc_proxy integer li_rc lsc_conn create soapconnection li_rc lsc_conn.createinstance( lsc_proxy, n_ws_userquery, http://server/app/service.wsdl, ServiceSoap) if li_rc 0 then MessageBox(错误, 创建WebService实例失败错误码 string(li_rc)) destroy lsc_conn return end if string ls_result try ls_result lsc_proxy.queryUser(10001) // 正常业务处理 catch (soapexception e) MessageBox(SOAP异常, e.getfaultstring()) end try destroy lsc_proxy destroy lsc_conn注意几个点lsc_conn和lsc_proxy都要创建用完都要销毁。createinstance返回0才是成功负数对应不同错误但光看错误码往往不够需要用GetLastError()拿到更详细的说明。如果应用里频繁调用同一个服务可以考虑把连接对象和代理对象定义为应用级或窗口级实例变量只初始化一次避免每次都解析WSDL、创建连接。但要注意多线程场景下共用代理对象会有资源竞争老项目如果用了Service或Thread最好每个线程单独创建。3.2 CreateInstance的细节与异常捕获createinstance有四个参数代理实例、代理类名字符串、WSDL地址、PortName。第四个参数很多人会漏漏了或传空串结果就是创建实例失败或者创建成功了但访问方法时报错。WSDL地址支持http://也支持本地文件。线上环境我建议优先用本地文件后面讲坑的时候细说。调用代理方法时一定要包try-catch因为SOAP请求走网络不是本地函数调用什么状况都可能发生网络断、超时、服务端抛异常、返回格式不符。捕获soapexception后把getfaultstring()和getfaultcode()记录到日志文件方便后面定位。3.3 参数与返回值的常见处理方式简单类型参数直接传string、long、decimal都没问题。复杂类型要借助代理生成的结构体类先create对象给属性赋值再作为参数传入。PB项目里最常见的复杂参数其实是数据窗口。平时业务数据都在DataWindow里接口需要传单据列表、明细数组我的做法是先把DataWindow序列化成XML字符串再作为string参数传出去。示例string ls_xml dw_detail.SaveAs(C:\temp\detail.xml, XML!, EncodingUTF8!) // 再把文件内容读成字符串赋给ls_xml服务端返回的也是XML时用XMLDOM对象解析比较直接。PB 2017 R3以后自带JSON解析器如果是JSON格式直接用JSONParser。老项目没这个待遇只能正则加字符串截取效率低但能用。能用WebService把数据送出去、收回来就已经解决系统集成的大半问题。4. 我在实际项目里踩过的坑超时、转发和证书4.1 连接超时不是只能干等有个项目调用客户方接口第一次总是很慢数据量大处理时间长默认超时时间到了才报错。SoapConnection老版本没有太灵活的超时控制新版本有Timeout属性或SetTimeout方法可以按业务情况调整。注意不同PB版本的单位有差异有的按秒有的按毫秒改之前查一下当前版本帮助文档别想当然地写个 60 就把超时设成了60毫秒。超时时间也不是越大越好对于长时间运行的批量接口建议把超时调大同时服务端配合做异步处理客户端侧做进度提示不要让用户以为程序死了。4.2 WSDL每次加载的问题与本地文件方案createinstance每次都会去拉WSDL。远程WSDL一旦服务不稳调用就偶发失败服务端重启间隙你正好去调也会报错。这种问题排查起来非常难受因为不能稳定复现。我的方案是第一次拿到WSDL文件后连同里面 import 的XSD一起下载到客户端安装目录用file:///C:/soapdef/service.wsdl这种方式加载。这样启动快、不受服务端WSDL状态影响。但这里有个大坑WSDL文件里如果 import 了外部 schema并且 schemaLocation 写的是远程HTTP地址即使你用本地WSDLPB运行时还是会去远程下载这些XSD。必须手动把XSD下载到同一个目录并把WSDL文件里的 import 路径改成相对路径比如schemaLocationservice.xsd。这个步骤漏了你会发现换了本地文件照样卡。4.3 HTTPS证书和自签名证书的坑客户环境启用HTTPS后PB客户端突然调不通错误提示五花八门。最常见的原因就是证书不被系统信任。WebService跑在公网上用自签名证书或测试证书PB客户端是不认的。处理办法按优先级排序把服务器证书导入客户端机器“受信任的根证书颁发机构”存储区。运维可以在域环境里批量下发省得一台台装。PB 2017及以上版本支持SetCertificateVerification可以控制证书校验的开关。但生产环境不建议全局关闭校验除非你有绝对把握网络环境可信。测试环境为了快速验证可以先用HTTP打通流程再切HTTPS避免把HTTP和证书问题混在一起排查。另外证书过期很容易被忽略。客户端报连接失败时先用浏览器访问一下WSDL地址如果浏览器提示证书不合法先让服务端刷新证书别在PB代码里瞎试。4.4 中文乱码到底出在哪SOAP协议默认UTF-8PB内部字符串处理又习惯用本机ANSI编码通常是GBK两边一碰就乱码。最常见的两种现象一是服务端返回中文PB界面显示乱码。这种要看服务端响应头里是否声明了charset如果服务端返回的XMLContent-Type没带charset或写的是GBKPB按UTF-8解析就乱了。最省事的处理是让服务端统一返回UTF-8并把Content-Type写完整。二是PB把中文参数传给服务端对方收到乱码。PB发送SOAP请求时如果请求头没正确声明编码服务端可能按默认编码解析导致中文错乱。用SetOptions方法给SOAP请求补上正确的Content-Type头一般就能解决。如果服务端不能改PB侧想靠转码函数硬救比较困难。因为SoapConnection已经把返回内容解析成字符串了编码错误发生在更底层拿到手的就是乱码。这种情况只有自己拼HTTP请求、自己解析SOAP响应或者让服务端配合改编码没有捷径。4.5 代理服务器、防火墙与网络策略PB客户端部署在客户内网想去调互联网上的服务得走HTTP代理。新版本SoapConnection提供了ProxyServer、ProxyPort这类属性可以设置代理。老版本这些支持不完善或者设了不生效就麻烦了。我遇到过的实战情况是网络团队给客户端所在网段开通到目标服务IP和端口的白名单直连访问不走代理。这样客户端零配置也省得处理代理认证、代理超时这些问题。调不通的时候先让网络同事用telnet或nc从客户端机器测到服务端IP端口的连通性网络不通PB代码写得再对也没用。5. 常见错误速查与调试思路5.1 CreateInstance返回负数问题不一定在PBCreateInstance返回非0按概率排序大概是这几个原因返回码/现象最可能原因排查方向-1 或异常运行时DLL不全检查pbsoapclient版本网络类错误WSDL地址不通浏览器访问WSDL验证无法解析WSDLXSD import 失败检查本地WSDL的schema路径创建成功但方法调用失败PortName错误对照WSDL确认port证书/加密错误HTTPS证书不受信浏览器访问验证证书记住一个原则PB只是SOAP客户端网络层和服务端的锅占大头。先用浏览器访问WSDL能打开说明网络通再用SoapUI从另一台机器调用服务能调通说明服务本身没问题。这两步排完剩下的才是PB侧的配置和代码问题。5.2 SOAP异常信息别只看弹窗服务端业务逻辑抛异常时SOAP会把异常包在返回报文里。PB捕获的soapexception对象有getfaultcode和getfaultstring这两个字段一定要记下来发给服务端开发人员他们一眼就能看出是参数不对还是业务规则被违反。很多时候对方会说“我这边日志没报错”你把faultstring里带的事务编号、明细行号贴过去对方马上知道去查哪条记录。这也是我为什么建议代码里不要只弹个MessageBox要在调用前后写日志。线上问题没有日志全靠猜效率太低。5.3 抓包能看穿80%的参数问题实在排查不动时上抓包工具。PB在客户端发HTTP请求用Fiddler或Wireshark能看到完整的SOAP请求和响应报文。重点看三块请求的Content-Type是否包含正确的charset。SOAP Body里的参数名和值是否符合WSDL定义。服务端返回的HTTP状态码和SOAP Fault内容。有次对方接口一直报参数缺失我抓包一看PB发的SOAP报文里节点名被代理类转换得跟WSDL不一致改一下代理类的属性映射就好。这种问题不看报文纯靠代码review很难发现。5.4 用最小案例复现问题维护老项目最忌讳直接拿正式的大接口调试。我的习惯是先在本地起一个最简单的WebService方法就一个接收string参数返回一个固定string。用PB客户端调通这个简单服务确认运行时DLL、网络链路、证书这些都正常再把代理类换成真实业务接口。这样做的好处是一旦真实接口调不通你能快速定位是接口本身的问题还是PB调用环境的问题。很多新手被大接口绕晕就是因为把环境问题和业务问题混在一起排查了一整天也没结论。最后说点我自己的操作习惯在实际项目里摸爬滚打之后我给自己定了一套规矩PB调WebService第一件事不是写代码而是把环境跑通。运行时DLL带齐WSDL和XSD文件放本地用浏览器确认服务可达再写一个hello world级别的调用验证链路。这四步做完后面接真实接口基本就是填参数的事出错概率大幅下降。另外一个实用小技巧把WSDL和XSD放在客户端安装目录的soapdef子目录代码里用file:///方式引用。这样应用启动快也不怕服务端WSDL临时抽风。这个习惯我保持了很多年在多个老项目里都验证过值得你试试。PB调用WebService这事原理不复杂难的是把环境、编码、证书这些外围因素都伺候好外围理顺了剩下的就是复制粘贴的体力活。本文还有配套的精品资源点击获取
返回列表