1

コンピューターで実行している HTTP サーバーに SOAP 通知を定期的に送信するデバイスがあります。通知は次のようになります。

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body>
        <Notify>
            <DeviceNotification message= "
                    <NotificationEvent NotificationType="Location">
                            <ComputerLocation changedOn="1369757031051">
                            </ComputerLocation>
                    </NotificationEvent>
                "/>
        </Notify>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

これは、タイプ DeviceNotification のインスタンスの XML 表現を含む SOAP エンベロープです。

これらの通知をどのように処理するかはよくわかりません (私のプログラムがサーバーかクライアントかのように)。通知はコマンドへの応答のように見えますが、実際にはリモート サービスを呼び出しているわけではありません (通知を送信するマシンには、「通知の宛先: この ip、このポート」を入力する Web インターフェイスがあり、送信を開始しますそれら) 通知の SOAP が完全に正しいかどうかもわかりません。

私はいくつかのSOAPライブラリなどを試しました...私が達成できた最も近いものは、spyneを使用することだと思います(または、おそらく単なる蜃気楼であり、他のライブラリよりも多くのものを出力するためだと思います)

class DeviceNotification(ComplexModel):
        ___namespace__ = ""
        pass

class HelloWorldService(ServiceBase):
    @rpc(DeviceNotification, _returns=Iterable(Unicode))
    def Notify(message):
        logging.warn("CHECKPOINT")
        print "message: %s" % message
        return ["foobarbaz"]

if __name__=='__main__':
    from wsgiref.simple_server import make_server
    PORT=7171
    application = Application([HelloWorldService],
                tns="",
                in_protocol=HttpRpc(validator='soft'),
                out_protocol=JsonDocument()
            )
    wsgi_application = WsgiApplication(application)
    server = make_server('', PORT, wsgi_application)
    server.serve_forever()

ただし、Notify関数が呼び出されることはありません。私は得る:

192.168.1.33 - - [28/May/2013 21:16:52] "POST / HTTP/1.1" 404 130
DEBUG:spyne.server.wsgi:Method name: '{}'
DEBUG:spyne.protocol.http:  header : {'soapaction': ['Notify'], 'host': ['niuyorker.jome:7171'], 'user_agent': ['Jakarta Commons-HttpClient/3.1']

そして、これは私が得る最も近いものです。その SOAP メッセージは正しいですか? そうである場合、これをサーバー (サーバー) への要求として扱うか、応答として扱うか (したがって、アプリケーションはクライアントになります)。Python と SOAP を使用して、2 つの数字を追加したり、「こんにちは」と何度も言ったりするよりも少し複雑な例を見つけられる場所を誰かが知っていれば、それも役に立ちますか?

いつでもlxmlを使用してSOAPメッセージ全体を解析できると思いますが、可能であればもう少し「専門的に」行いたいと思います。気付いていないかもしれませんが、私は SOAP サービスの初心者です。:)

前もって感謝します!

アップデート:

メッセージ部分は実際にはエスケープされた XML である必要があるように見えますが、これは...まあ...それは私が最初から実際に取得していたものですが、(私は初心者です)質問でよりきれいに見えるようにエスケープしました。本当は:

 <soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
 <soap-env:body>
  <notify>
   <notification message='&lt;NotificationEvent NotificationType="Location"&gt;&lt;DeviceLocation changedOn="1369074622065"&gt;&lt;/DeviceLocation&gt;&lt;/NotificationEvent&gt;'>
   </notification>
  </notify>
 </soap-env:body>
</soap-env:envelope>

私はWSDLを持っています。sudsを使用して、次のような「ComputerLocation」タイプのインスタンスを作成できました。

>>> from suds.client import Client
>>> url="file:///tmp/service.wsdl"
>>> c=Client(url)
>>> c.factory.create('DeviceLocation')
(DeviceLocation){
   _changedOn = ""
 }

しかし、それは私ができることのほとんどすべてです。

正直なところ、サーバーが必要かクライアントが必要かはまだわかりません...

4

2 に答える 2

1

in_protocol=HttpRpcの代わりに使用していますin_protocol=Soap11

HttpRpcプロトコルは次のように簡単に定義されます。

いわゆる ReST っぽい HttpRpc プロトコルの実装。

これが何を意味するのかは完全には明らかではありませんが、SOAP 1.1 メッセージを解析してコマンドを見つけようとしないことをお勧めします。


これを過ぎて、更新された(正しい)例を与えてください:

これは有効な XML として解析され、有効な SOAP 1.1 エンベロープに含まれています。

しかし、それはまだ良いSOAP ではありません。本文の内容は名前空間化されておらず、パラメーターを持つ構造化オブジェクトでもありません。実際、コンテンツ全体が 1 つの汎用 XML ツリーであり、実際のコンテンツは別の汎用 XML ツリーであり、外側のツリーのノードの属性としてエスケープされた形式で格納されます。

あなたの1つの例の外観から、URLパスは常にであり、SOAP構造は常にSOAPエンベロープ内の直接/の単一であると推測します。Notify確かに、フレームワークと十分に戦えば、おそらくそれを でディスパッチすることができますがNotify、いずれにせよすべてのメッセージが同じ場所に送られることになります。おそらくディスパッチしたいのは、埋め込まれた XML の中にあるNotificationType.

これらの推測が正しければ、使用方法を知っている最も馴染みのある Web サーバーを使用してください。実際には WSGI は必要ありません。必要に応じて簡単なハンドラーを作成http.server.HTTPServerし、すべてのメッセージを同じコードにルーティングします。これにより、NotificationEventオブジェクトに到達してそこからディスパッチするのに十分な解析が行われます。このようなもの:

from xml.etree import ElementTree as ET

def handle_location(nevent):
    clocation = nevent.find('ComputerLocation')
    changed_on = clocation.attrib['changedOn']
    location = clocation.text
    # do something with this info

def handle_other_thing(nevent):
    # whatever

handlers = {'Location': handle_location,
            'OtherThing': handle_other_thing }

et = ET.fromstring(body)
for notification in et.iter('notification'):
    message = ET.fromstring(notification.attrib['message'])
    for nevent in message.iter('NotificationEvent'):
        ntype = nevent.attrib['NotificationType']
        handlers[ntype](nevent)

内の最下位レベルのフィールドに WSDL を使用している可能性があるため、そのレベルに到達したら etree を手動で解析する代わりにNotificationEvent使用できます。これにより、作業が楽になり、コードがより柔軟になります。suds

そしてもちろん、いくつかのエラー処理を追加したいと思うでしょう。

于 2013-05-28T23:40:46.533 に答える