首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Delphi Onvif SOAP调用

Delphi Onvif SOAP调用
EN

Stack Overflow用户
提问于 2014-09-28 19:06:22
回答 2查看 3.4K关注 0票数 0

我想开始使用Delphi来访问和控制带有Onvif SOAP协议的IP摄像机。

但是,我不明白如何实际执行来自Delphi的调用。我导入了以下WDSL:

http://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl

在Delphi中生成了一个单元。但是我该如何处理对着摄像机的呼叫呢?我应该以某种方式使用与THTTPRIO一起生成的这个吗?如何指定我拥有的相机的IP地址(目前是Axis Q1755摄像机)。

如果有人能让我从正确的方向开始,我将非常感激。

EN

回答 2

Stack Overflow用户

发布于 2014-09-28 20:16:15

如果您使用Delphi的WSDL导入程序,它将生成必要的类来表示来自SOAP its服务及其相应的response的任何response

它还将生成一个wrapper,您将使用它来实际执行调用。通常,它将有以下几种方法:

代码语言:javascript
复制
function mySoapMethod(myRequest: TmyRequestType): TMyResponse;

要打电话,你基本上可以做以下几件事:

  1. 获取一个wrapper实例引用。单元中应该有一个类似于GetWrapper的方法。
  2. 如果有必要,可以为request type创建一个实例,并设置其所有属性。请注意,如果SOAP方法只需要几个基本类型作为参数,就可能没有这样的请求类。还要考虑到,任何足够复杂的request type都可能意味着您需要创建对象的实例,并将它们作为属性分配给请求。
  3. 使用相应的wrapper method发送请求(如果是简单调用,则设置参数)。
  4. 接收response对象并根据需要对其进行操作。

在伪码中如下所示:

代码语言:javascript
复制
myWrapper := GetMyWrapper();
myRequest := TMyRequest.Create;
//set myRequest properties
myResponse := myWrapper.mySoapMethod(myRequest);
//do whatever you need with the response

关于包装器

wrapper将是带有一些新增方法的IInvokable接口的实现。实际上,对于您可以调用的每个SOAP method,它都应该有一个方法。

通常,它的接口声明如下所示:

代码语言:javascript
复制
TmyWrapper = interface(IInvokable)
['...'] //GUID here
  function oneMethod(...): oneMethodResponse;
  function anotherMethod(...): anotherMethodResponse;
end;

function getMyWrapper(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): TmyWrapper ;

该函数的实现将如下所示:

代码语言:javascript
复制
function GetMyWrapper(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): TmyWrapper;
const
  defWSDL = 'http://<soap service IP and port>/<soap service name>?wsdl';
  defURL  = 'http://<soap service IP and port>/<soap service name>';
  defSvc  = '<default service name>';
  defPrt  = '<default service port>';
var
  RIO: THTTPRIO;
begin
  Result := nil;
  if (Addr = '') then
  begin
    if UseWSDL then
      Addr := defWSDL
    else
      Addr := defURL;
  end;
  if HTTPRIO = nil then
    RIO := THTTPRIO.Create(nil)
  else
    RIO := HTTPRIO;
  try
    Result := (RIO as TmyWrapper );
    if UseWSDL then
    begin
      RIO.WSDLLocation := Addr;
      RIO.Service := defSvc;
      RIO.Port := defPrt;
    end else
      RIO.URL := Addr;
  finally
    if (Result = nil) and (HTTPRIO = nil) then
      RIO.Free;
  end;
end;

一些附带说明:

  • 当您通过使用HTTPRIO方法获得wrapper实例时,您可以将它注入到getXYZWrapper实例。例如,这可以帮助您设置另一个SOAP URL或检查生成的XML
  • 有时候,德尔菲生成的XML将按照SOAP的预期以一种稍微不同的方式发送。如果您认为它应该工作,但不工作,那么检查生成的XML并将它与它应该是什么相比较。在发送HTTPRIO对象的onBeforeExecute事件之前,可以使用它来修改XML
  • 如果您需要它,还可以使用HTTPRIO对象的HTTPRIO方法来检查XML响应。
票数 1
EN

Stack Overflow用户

发布于 2019-07-24 07:52:33

您可以通过Delphi XE7使用我导入的WSDL

媒体:Media.WSDL

成像:Imaging.wsdl

设备管理:devicemgmt.wsdl

通常导入的WSDL有一个函数,如

代码语言:javascript
复制
function GetMySoap(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): MySoap;

但是它不存在于onvif导入的wsdl中。

将此函数添加到项目实例中,Media2是IInvokable类的名称。

代码语言:javascript
复制
function GetWSSoap(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): Media2;
const
  defWSDL = 'http://192.168.1.1/onvif/Media?WSDL';
  defURL  = 'http://192.168.1.1/onvif/Media';
  defSvc  = 'Media';
  defPrt  = '80';
var
  RIO: THTTPRIO;
begin
  Result := nil;
  if (Addr = '') then
  begin
    if UseWSDL then
      Addr := defWSDL
    else
      Addr := defURL;
  end;
  if HTTPRIO = nil then
    RIO := THTTPRIO.Create(nil)
  else
    RIO := HTTPRIO;
  try
    Result := (RIO as Media2);
    if UseWSDL then
    begin
      RIO.WSDLLocation := Addr;
      RIO.Service := defSvc;
      RIO.Port := defPrt;
    end else
      RIO.URL := Addr;
  finally
    if (Result = nil) and (HTTPRIO = nil) then
      RIO.Free;
  end;
end;

另一种解决方案,使用发送http requst示例请求获取一些通用信息,GetProfiles是方法名称。

代码语言:javascript
复制
<?xml version="1.0"?> <soap:Envelope 
xmlns:soap="http://www.w3.org/2003/05/soap-envelope" 
xmlns:wsdl="http://www.onvif.org/ver10/media/wsdl">
<soap:Header>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1"> 
<UsernameToken> 
<Username>%s</Username> 
<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">%s</Password> 
<Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">%s</Nonce> 
<Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">%s</Created> 
</UsernameToken> 
</Security> 
</soap:Header>
<soap:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<GetProfiles xmlns="http://www.onvif.org/ver10/media/wsdl" /> 
</soap:Body> 
</soap:Envelope>

按钮代码:

ip:http://192.168.1.1

网址: onvif/media

代码语言:javascript
复制
  GetONVIFPasswordDigest(ed_user.text, ED_pass.text, PasswordDigest, Nonce, Created);
  User_Pass := Format(M_Request, [UserName, PasswordDigest, Nonce, Created]);
  ONVIFRequest(ED_IP.Text + ED_URL.Text,User_Pass,Result);

密码制作程序:

代码语言:javascript
复制
procedure GetONVIFPasswordDigest(const UserName, Password: String; Var PasswordDigest, Nonce, Created: String);
Var
  i: Integer;
  raw_nonce, bnonce, digest , S_In: TBytes;
  raw_digest: TBytes;
  DT : TDateTime;
begin
  SetLength(raw_nonce, 20);
  for i := 0 to High(raw_nonce) do
    raw_nonce[i] := Random(256);
  bnonce := TNetEncoding.Base64.Encode(raw_nonce);
  Nonce := BytesToString(bnonce);
  DT := Now();
  Created := GetONVIFDateTime(DT);
  S_In := raw_nonce + StringToBytes(Created) + StringToBytes(Password);
  raw_digest := SHA1(S_In);
  digest := TNetEncoding.Base64.Encode(raw_digest);
  PasswordDigest := BytesToString(digest);
end;

获取数据过程:

代码语言:javascript
复制
procedure ONVIFRequest(const Addr: String; const InStream, OutStream: TStringStream);overload;
Var
  idhtp1: TIdHTTP;
  Uri: TIdURI;
begin
  idhtp1 := TIdHTTP.Create;
  Uri := TIdURI.Create(Addr);
  try
    With idhtp1 do
    begin
      AllowCookies := True;
      HandleRedirects := True;
      Request.Accept := 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
      Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
      Request.Host := '';
      Request.Connection := '';
      Request.Accept := '';
      Request.UserAgent := '';

      Request.CustomHeaders.Clear;
      Request.ContentType := 'text/xml;charset=utf-8';
      Request.CustomHeaders.Add('Host: ' + Uri.Host);
      //-------------------
      request.username := ed_user.text;
      request.password := ed_pass.text;
      HTTPOptions := [hoInProcessAuth,hoForceEncodeParams,hoNoProtocolErrorException, hoWantProtocolErrorContent];
      //-------------------

      ProtocolVersion := pv1_1;
      Post(Addr, InStream, OutStream);
    end;
  finally
    Uri.Free;
    idhtp1.Free;
  end;
end;
procedure ONVIFRequest(const Addr, Request: String; Var Answer: String);overload;
Var
  InStream, OutStream: TStringStream;
begin
  InStream := TStringStream.Create(Request);
  OutStream := TStringStream.Create;
  try
    ONVIFRequest(Addr, InStream, OutStream);
    Answer := OutStream.DataString;
  finally
    InStream.Free;
    OutStream.Free;
  end;
end;

你也可以在这里找到一个更好的样本。

代码语言:javascript
复制
https://github.com/Laex/Delphi-ONVIF
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26088527

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档