直接用Qt写soap
最近的项目里用到了webservice, 同事用的是`gSoap`来搞的.
用这个本身没什么问题, 但这货生成的代码实非人类可读, 到处都是`__`和`_`, 看得我眼晕.....
其实项目里用的webservice很简单, 暂时只有身份验证这一个, 所以就想能不能直接用Qt搞定.
说搞就搞, 哪知一下就搞了1天半.....
把过程记录下来, 以防我的老脑筋忘记了 -_____-!
原理
我们用的webservice是基于xml的, 也叫soap.
而soap = http + xml, 所以原理就很简单了:
用QHttp直接连服务器, 将请求的内容以指定xml格式组织好后, POST到服务端就OK了
怎么样, 原理很简单吧, 但对于我这个从来没写过http请求的人来说, 还是出了不少的状况.
* 400 Bad Request
这个问题一般都是post写错了, 应该是大写`POST`才行.
* 500 interval server error
一开始一直都是400错误, 不停的改代码的过程中, 也出了几次500错误.
出现这个错误, 一般都是xml的格式有误导致的, 如我看网上写的会在xml的开头添加一个`
`, 我也加了, 结果就是这种错误.
** 注意事项 **
webservice中, 至少有两个header是必须填写的:
1. Content-Type
2. Content-Length
因为内容是xml格式的文本, 所以这两个必须写, 否则服务器无法正确解析.
代码
试验的时候, 用的是PyQt4写的, 所以这里就贴点这个代码吧:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtNetwork import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self._http = None
self.test()
def test(self):
http = QHttp('10.88.104.158')
self._http = http
data = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<UserLogin xmlns="http://www.richfit.com/">
<userLoginName>admin</userLoginName>
<userPwd>123</userPwd>
<appType>test</appType>
</UserLogin>
</soap:Body>
</soap:Envelope>'''
req = QHttpRequestHeader()
req.setRequest('POST', '/3DWebGIS/Services/DataService.asmx')
req.setValue('Host', '10.88.104.158')
req.setValue('Content-Type', 'text/xml; charset=utf-8')
req.setValue('Content-Length', str(len(data)))
req.setValue('SOAPAction', '"http://www.richfit.com/UserLogin"')
self.connect(self._http, SIGNAL('requestFinished(int, bool)'), self.finish)
cnt = data.encode('utf-8')
print http.request(req, cnt)
def test1(self):
import sys, httplib
data = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<UserLogin xmlns="http://www.richfit.com/">
<userLoginName>admin</userLoginName>
<userPwd>123</userPwd>
<appType>test</appType>
</UserLogin>
</soap:Body>
</soap:Envelope>'''
h = httplib.HTTP('10.88.104.158')
h.putrequest('POST', '/3DWebGIS/Services/DataService.asmx')
h.putheader('Host', '10.88.104.158')
h.putheader('User-Agent', 'Python post')
h.putheader('Content-Type', 'text/xml; charset="UTF-8"')
h.putheader('Content-length', str(len(data)))
h.putheader('SOAPAction', '"http://www.richfit.com/UserLogin"')
h.endheaders()
h.send(data)
sc, sm, header = h.getreply()
print sc, sm
print header
print h.getfile().read()
def finish(self, iid, ok):
print iid, ok
resp = self._http.lastResponse()
print resp.statusCode(), resp.reasonPhrase()
print str(self._http.readAll()).decode('utf-8')
app = QApplication(sys.argv)
frm = MainWindow()
frm.show()
app.exec_()
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtNetwork import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self._http = None
self.test()
def test(self):
http = QHttp('10.88.104.158')
self._http = http
data = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<UserLogin xmlns="http://www.richfit.com/">
<userLoginName>admin</userLoginName>
<userPwd>123</userPwd>
<appType>test</appType>
</UserLogin>
</soap:Body>
</soap:Envelope>'''
req = QHttpRequestHeader()
req.setRequest('POST', '/3DWebGIS/Services/DataService.asmx')
req.setValue('Host', '10.88.104.158')
req.setValue('Content-Type', 'text/xml; charset=utf-8')
req.setValue('Content-Length', str(len(data)))
req.setValue('SOAPAction', '"http://www.richfit.com/UserLogin"')
self.connect(self._http, SIGNAL('requestFinished(int, bool)'), self.finish)
cnt = data.encode('utf-8')
print http.request(req, cnt)
def test1(self):
import sys, httplib
data = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<UserLogin xmlns="http://www.richfit.com/">
<userLoginName>admin</userLoginName>
<userPwd>123</userPwd>
<appType>test</appType>
</UserLogin>
</soap:Body>
</soap:Envelope>'''
h = httplib.HTTP('10.88.104.158')
h.putrequest('POST', '/3DWebGIS/Services/DataService.asmx')
h.putheader('Host', '10.88.104.158')
h.putheader('User-Agent', 'Python post')
h.putheader('Content-Type', 'text/xml; charset="UTF-8"')
h.putheader('Content-length', str(len(data)))
h.putheader('SOAPAction', '"http://www.richfit.com/UserLogin"')
h.endheaders()
h.send(data)
sc, sm, header = h.getreply()
print sc, sm
print header
print h.getfile().read()
def finish(self, iid, ok):
print iid, ok
resp = self._http.lastResponse()
print resp.statusCode(), resp.reasonPhrase()
print str(self._http.readAll()).decode('utf-8')
app = QApplication(sys.argv)
frm = MainWindow()
frm.show()
app.exec_()
这里其实提供了两种方式来实现soap请求的, 其中`test`是用qt的方案实现的, `test1`用的是最原始的方法实现的.
这里的东西在原理部分都可以对照上, 只有一点要注意一下:
http = QHttp('10.88.104.158')
h = httplib.HTTP('10.88.104.158')
h = httplib.HTTP('10.88.104.158')
这两句里的地址**不能**带`http://`哦!!
参考资料: