背景
项目的业务流程中有一个环节,需要访问供应商提供的web service。不同于公共的服务,由于系统涉及财务,这个服务必须通过认证才能访问。认证的方式是NTLM,是一种windows特有的认证方式,而常规的Http认证会报401错误。
常规的处理思路是用大名鼎鼎的suds库(python3环境下,需要suds-jurko + suds-py3这两个库搭配使用)来创建一个Client示例,然后直接打点访问对应的SOAP方法。类似的代码网上随处可见,我就不写了。我这里却遇到了问题(ntml-auth库报错),而不得不另寻出路。
思路
我们都知道SOAP协议,其实也是源自HTTP协议传输的,只是通过XML对方法做了预定义,相比较常见的开放接口而言,WSDL具有很好的方法发现特效。
既然如此,那我们完全可以用http的方式去调用,只要我们自己能够处理好认证、报文和http头即可。
需要用到的库
- requests
- requests-ntlm
代码示例
import requests
from requests_ntlm import HttpNtlmAuth
url = "http://xxxx/aaaaa/bbbb/cccc"
username = "username"
password = "password"
headers = {
"Content-Type": "text/xml",
"SOAPAction": "action" # 你要访问的方法名。必填,否则无法访问到方法,这个地方卡我好久
}
postcontent='<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><action xmlns="urn:microsoft-dynamics-schemas/codeunit/cccc"><p1>6541</p1><p2>0</p2></action></soap:Body></soap:Envelope>'
req = requests.post(url, headers=headers, auth=HttpNtlmAuth(username, password), data=postcontent.encode('utf-8'))
print(req, req.text)
要点讲解
- 报文尽量一行写完,别换行。由于提供的web service是由版本比较低的Nav提供的,xml格式并不是特别规范,如果我们的报文有回车、制表符等字符的话,会报500错误,提示无效的数据。
- SOAP的报文,可以通过下一节提到的接口测试工具SoupUI得到。
- headers里的Content-Type和SOAPAction都是必填的。Content-Type固定写text/xml,SOAPAction写你要调用的方法名。
- requests想通过NTLM认证,需要配合使用requests_ntlm.HttpHtlmAuth。
接口测试工具
我们在开始写代码之前,可以先用接口测试工具检查一下接口的访问性。这里推荐两个工具,(1)SoupUI,(2)Postman
1. SoupUI
操作步骤如图:
(1)创建SOAP项目
(2)获取方法,替换参数并运行
soupui-2.png
上图第2步所指的XML就是报文了,我们可以复制下来写在python里。
(3)如果需要认证,请看这里
soupui-3.png
理论上SoupUI就能搞定的ws,可以直接用suds来操作。
2. Postman
SoupUI成功了,就可以用Postman来模拟HTTP Request了。这一步再成功了,python下实现就轻而易举了。
操作请看图:
(1)认证这样写,注意TYPE选择NTLM Authentication
postman-1.png
(2)头信息这么写
postman-2.png
(3)报文这么写,要在Body里选择raw,soap:body尽量别换行,整体不换行也没问题
postman-3.png
小结
感觉现在用web service的人很少,所以遇到问题可查阅的资料就更少了。到现在为止,我也不知道自己用suds配合ntlm-auth做的报错原因是什么,不过可以确定的是,错误出在认证这块,不知道是这个wsdl不规范导致ntlm-auth出现了兼容性问题,还是这个库本身就有bug存在。
常规的postman/requests访问web service,网上的资料几乎都有说在headers里加Content-Type的,但是这个SOAPAction几乎没有人提到,要不是我这边瞎几把试,给试出来,我也不知道这个参数这么重要。没有它,只会返回WSDL定义。
这次的头疼之路,通过SoupUI -> Postman -> request 这样的路径解决了。核心就是解决了ntlm验证之后,header里加上SOAPAction这个字段。
这次的事情和爱人讲了,她立刻想到一部讲述图灵的电影(名字忘记了),大概就是图灵在破译敌方电报情报时,通过在电报的头信息里构造了一些数字之后,就成功的破译了,听起来似乎和我这次遇到的情况很像呢。
网友评论