背景

之前的文章已经讲述了如何通过ONVIF广播和组播发现设备,以及如何解析xml文件。在进行ONVIF服务调用之前,还需要再补充一下SOAP和http方面的内容。因为ONVIF就是使用SOAP和http进行接口调用的。本文会讲述一下web service、soap和http之间的关系,以及怎么调用soap。

文章发表的顺序可能有点乱,麻烦根据《基于ONVIF协议的摄像机监控管理平台(1)概述》里面的文章目录进行阅读,抱歉了


《基于ONVIF协议的摄像机监控管理平台(3)使用组播搜索发现设备WS-Discovery》
《基于ONVIF协议的摄像机监控管理平台(4)使用广播搜索发现设备WS-Discovery》
《基于ONVIF协议的摄像机监控管理平台(5)XML解析》



一、 webservice,SOAP和http的关系

关于概念的问题我就不多说了,直接引用一下网上的叙述吧。需要更详细的资料的,请自行google。

Web service就是一个能够通过Web进行API调用的服务程序,基本的目的就是提供在各个不同平台的不同应用系统的协同工作能力,SOAP是web service的其中一种。



SOAP是基于xml的轻量协议,用于在web上交换结构化信息和类型信息。

SOAP请求是HTTP POST的一个专用版本,遵循一种特殊的xml消息格式,http的Content-type设置为:text/xml。soap中的所有数据都用xml表示。

二、怎么使用SOAP Web Service

  1. 所有的API调用,都是客户端发送一个请求,然后服务端返回一个结果。
  2. SOAP Web Service是发送一个http post请求,得到一个服务端返回结果。
  3. 发送和接收的数据都是通过 XML格式表示。
  4. 熟悉WCF开发的话,可以使用WCF进行调用。
  5. 用c/c++的开发者,使用gSOAP可以简化很多工作。
  6. 还有一种方法,就是用 http的库和xml的库,发送请求和解析结果。

三、用浏览器模拟一下

  1. 如果用浏览器地址直接访问服务地址,一般是报错或者没反应的。浏览器地址栏发起的是http get请求。例如我访问摄像头服务地址。
http://192.168.110.163/onvif/device_service

得到的结果是



 <?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:xmime4="http://www.w3.org/2004/11/xmlmime" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:tes-e="http://www.onvif.org/ver10/events/wsdl/EventBinding" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tes-nc="http://www.onvif.org/ver10/events/wsdl/NotificationConsumerBinding" xmlns:tes-np="http://www.onvif.org/ver10/events/wsdl/NotificationProducerBinding" xmlns:tes-sm="http://www.onvif.org/ver10/events/wsdl/SubscriptionManagerBinding" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:xmime="http://www.w3.org/2004/06/xmlmime" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" 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" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tan-ae="http://www.onvif.org/ver20/analytics/wsdl/AnalyticsEngineBinding" xmlns:tan-re="http://www.onvif.org/ver20/analytics/wsdl/RuleEngineBinding" xmlns:trc="http://www.onvif.org/ver10/recording/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tse="http://www.onvif.org/ver10/search/wsdl" xmlns:tpl="http://www.onvif.org/ver10/plus/wsdl" xmlns:tplt="http://www.onvif.org/ver10/plus/schema">
    <SOAP-ENV:Body>
        <SOAP-ENV:Fault>
            <faultcode>SOAP-ENV:Client</faultcode>
            <faultstring>HTTP GET method not implemented</faultstring>
        </SOAP-ENV:Fault>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

很明显就是出错了。

  1. 如果想用模拟POST请求,可以利用浏览器的插件或者其它第三方软件来实现。我这里用的Chrome浏览器的postman插件。有需要的可以去看一下我的另外几篇文章。
    《利用chrome插件postman,模拟http post请求》
    《利用chrome插件postman,模拟 SOAP 调用》
    《利用SoapUI模拟onvif接口调用请求》



  2. 下面简要说一下使用postman模拟soap接口调用。
    安装和使用教程可以参考这篇文章。
    《Postman用法简介-Http请求模拟工具》

  • 在chrome中安装postman;
  • 请求方法设置为 POST;
  • 填写ONVIF服务地址,例如 http://192.168.110.163/onvif/device_service;
  • Auth那里可以选择No Auth(前提是调用的那个接口是不需要认证的,我这里举一个读取系统时间的接口为例,不需要认证)。如果需要了解关于认证和鉴权方面的,可以查看我另外一篇文章。《基于ONVIF协议的摄像机监控管理平台(8)鉴权和认证》
  • 填写 Header;
    • (1)新增一个key为 SOAPAction
    • (2)value为 https://www.onvif.org/ver10/device/wsdl/GetSystemDateAndTime
  • 填写 body,body选项设置为Raw(下面这段是我用wireshark抓包抓出来的,复制粘贴到body那里即可);
 <?xml version="1.0" encoding="utf-8"?>
<s:Envelope
    xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Body
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <GetSystemDateAndTime
            xmlns="http://www.onvif.org/ver10/device/wsdl"/>
        </s:Body>
    </s:Envelope>
  • 最后,可以得到返回结果如下。
 <?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:xmime4="http://www.w3.org/2004/11/xmlmime" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:tes-e="http://www.onvif.org/ver10/events/wsdl/EventBinding" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tes-nc="http://www.onvif.org/ver10/events/wsdl/NotificationConsumerBinding" xmlns:tes-np="http://www.onvif.org/ver10/events/wsdl/NotificationProducerBinding" xmlns:tes-sm="http://www.onvif.org/ver10/events/wsdl/SubscriptionManagerBinding" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:xmime="http://www.w3.org/2004/06/xmlmime" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" 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" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tan-ae="http://www.onvif.org/ver20/analytics/wsdl/AnalyticsEngineBinding" xmlns:tan-re="http://www.onvif.org/ver20/analytics/wsdl/RuleEngineBinding" xmlns:trc="http://www.onvif.org/ver10/recording/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tse="http://www.onvif.org/ver10/search/wsdl" xmlns:tpl="http://www.onvif.org/ver10/plus/wsdl" xmlns:tplt="http://www.onvif.org/ver10/plus/schema">
    <SOAP-ENV:Body>
        <tds:GetSystemDateAndTimeResponse>
            <tds:SystemDateAndTime>
                <tt:DateTimeType>Manual</tt:DateTimeType>
                <tt:DaylightSavings>false</tt:DaylightSavings>
                <tt:TimeZone>
                    <tt:TZ>CST-8</tt:TZ>
                </tt:TimeZone>
                <tt:UTCDateTime>
                    <tt:Time>
                        <tt:Hour>3</tt:Hour>
                        <tt:Minute>54</tt:Minute>
                        <tt:Second>37</tt:Second>
                    </tt:Time>
                    <tt:Date>
                        <tt:Year>2011</tt:Year>
                        <tt:Month>12</tt:Month>
                        <tt:Day>1</tt:Day>
                    </tt:Date>
                </tt:UTCDateTime>
                <tt:LocalDateTime>
                    <tt:Time>
                        <tt:Hour>11</tt:Hour>
                        <tt:Minute>54</tt:Minute>
                        <tt:Second>37</tt:Second>
                    </tt:Time>
                    <tt:Date>
                        <tt:Year>2011</tt:Year>
                        <tt:Month>12</tt:Month>
                        <tt:Day>1</tt:Day>
                    </tt:Date>
                </tt:LocalDateTime>
            </tds:SystemDateAndTime>
        </tds:GetSystemDateAndTimeResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
  • 已经可以很清楚的看到年月日等信息了证明可以调用成功。

四、利用http库和XML库,调用SOAP服务和ONVIF接口

上面只是模拟一下SOAP请求而已,证明用http库来调用ONVIF应该是可行的。
下面继续请求上面的那个时间接口吧。下面举个c#的例子说明一下,其他语言的我就不多说了。

        //这里用的是异步方法
        private async void HttpPostTest()
        {
            //ONVIF服务所在的地址
            var url = "http://192.168.110.163/onvif/device_service";
            //创建一个http请求
            using (var client = new HttpClient())
            {
                //清楚http请求的所有默认Header
                client.DefaultRequestHeaders.Clear();
                //在Header中添加SOAPAction
                client.DefaultRequestHeaders.Add("SOAPAction", "https://www.onvif.org/ver10/device/wsdl/GetSystemDateAndTime");
                //这段xml字符串用xml库生成更好,如果有些多余的空格可能会请求失败
                String xmlPost = "<?xml version=\"1.0\" encoding=\"utf - 8\"?> <s:Envelope xmlns:s = \"http://www.w3.org/2003/05/soap-envelope\" ><s:Body xmlns:xsi = \"http://www.w3.org/2001/XMLSchema-instance\" xmlns: xsd = \"http://www.w3.org/2001/XMLSchema\" ><GetSystemDateAndTime xmlns = \"http://www.onvif.org/ver10/device/wsdl\" /></s:Body ></s:Envelope > ";
                Console.WriteLine(xmlPost);
                //设置一下 http post的格式
                var content = new StringContent(xmlPost, Encoding.UTF8, "application/xml");
                //发起请求
                var response = await client.PostAsync(url, content);
                //查看响应信息
                var responseString = await response.Content.ReadAsStringAsync();
                Console.WriteLine(responseString.ToString());
            }
        }

不过其中有行代码是需要特别描述一下的。

<?xml version="1.0" encoding="utf - 8"?>
<s:Envelope xmlns:s = "http://www.w3.org/2003/05/soap-envelope" >
<s:Body xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns: xsd = "http://www.w3.org/2001/XMLSchema" >
<GetSystemDateAndTime xmlns = "http://www.onvif.org/ver10/device/wsdl" />
</s:Body >
</s:Envelope >

这个xml用xml库生成会更好,如果复制黏贴时,多了一些多余的空格就会报错。另外,复制黏贴还需要给双引号增加反斜杠的转义符,同时要修改某部分字符的时候也不太灵活。这里举例,就不说太清楚了。

如果上面的字符串多了些不合适的空格,或者其他错误之类,可能会收到如下的应答。

<?xml version="1.0" encoding="utf-8"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:xmime4="http://www.w3.org/2004/11/xmlmime" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:tes-e="http://www.onvif.org/ver10/events/wsdl/EventBinding" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tes-nc="http://www.onvif.org/ver10/events/wsdl/NotificationConsumerBinding" xmlns:tes-np="http://www.onvif.org/ver10/events/wsdl/NotificationProducerBinding" xmlns:tes-sm="http://www.onvif.org/ver10/events/wsdl/SubscriptionManagerBinding" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:xmime="http://www.w3.org/2004/06/xmlmime" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" 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" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tan-ae="http://www.onvif.org/ver20/analytics/wsdl/AnalyticsEngineBinding" xmlns:tan-re="http://www.onvif.org/ver20/analytics/wsdl/RuleEngineBinding" xmlns:trc="http://www.onvif.org/ver10/recording/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tse="http://www.onvif.org/ver10/search/wsdl" xmlns:tpl="http://www.onvif.org/ver10/plus/wsdl" xmlns:tplt="http://www.onvif.org/ver10/plus/schema">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <SOAP-ENV:Code>
        <SOAP-ENV:Value>SOAP-ENV:Sender</SOAP-ENV:Value>
      </SOAP-ENV:Code>
      <SOAP-ENV:Reason>
        <SOAP-ENV:Text xml:lang="en">Well-formedness violation</SOAP-ENV:Text>
      </SOAP-ENV:Reason>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

后记

有任何的疑问或者想法,或者对本文有质疑或者补充的话,欢迎在留言区评论,期待你的分享!


同时,也欢迎关注本人微信公众号或者打赏一下这篇文章。



http://xzh.i3geek.com

爱唠叨的老鱼

爱唠叨的老鱼

技术经理,个人站长,创业者

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据