Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (中文) » SQL Anywhere 服务器 - 编程 » SQL Anywhere 数据访问 API » SQL Anywhere Web 服务

 

处理 SOAP 标头

在本节中,会将使用 SOAP 服务中所介绍的简单 Web 服务扩展到处理 SOAP 标头。

如果您已执行上一节中概述的步骤,则可以跳过第 1 步到第 4 步,直接进行第 5 步。

♦  创建 Web 服务服务器
  1. 创建数据库。

    dbinit ftc
  2. 使用此数据库启动一个服务器。

    dbsrv11 -xs http(port=8082) -n ftc ftc.db
  3. 使用 Interactive SQL 连接到该服务器。

    dbisql -c "UID=DBA;PWD=sql;ENG=ftc"
  4. 使用 Interactive SQL 创建一个 Web 服务。

    CREATE SERVICE FtoCService
    TYPE 'SOAP'
    FORMAT 'XML'
    AUTHORIZATION OFF
    USER DBA
    AS CALL FToCConvertor( :temperature );
  5. 定义此服务要调用的用来执行从华氏温度转换为摄氏温度所需计算的存储过程。与上一节中的示例不同,此示例包含其它语句用以处理特殊 SOAP 标头。如果您已完成了上一节中的示例,则将下面的 CREATE 更改为 ALTER,因为您现在要修改该存储过程。

    CREATE PROCEDURE FToCConvertor( temperature FLOAT )
    BEGIN
      DECLARE hd_key LONG VARCHAR;
      DECLARE hd_entry LONG VARCHAR;
      DECLARE alias LONG VARCHAR;
      DECLARE first_name LONG VARCHAR;
      DECLARE last_name LONG VARCHAR;
      DECLARE xpath LONG VARCHAR;
      DECLARE authinfo LONG VARCHAR;
      DECLARE namespace LONG VARCHAR;
      DECLARE mustUnderstand LONG VARCHAR; 
    header_loop:
      LOOP
        SET hd_key = NEXT_SOAP_HEADER( hd_key );
        IF hd_key IS NULL THEN
          -- no more header entries
          LEAVE header_loop;
        END IF;
        IF hd_key = 'Authentication' THEN
          SET hd_entry = SOAP_HEADER( hd_key );
          SET xpath = '/*:' || hd_key || '/*:userName';
          SET namespace = SOAP_HEADER( hd_key, 1, 
                                   '@namespace' );
          SET mustUnderstand = SOAP_HEADER( hd_key, 1, 
                                   'mustUnderstand' );
          BEGIN
            -- parse the XML returned in the SOAP header 
            DECLARE crsr CURSOR FOR 
              SELECT * 
              FROM OPENXML( hd_entry, xpath )
                WITH ( alias LONG VARCHAR '@*:alias',
                first_name LONG VARCHAR '*:first/text()',
                last_name LONG VARCHAR '*:last/text()' );
            OPEN crsr;
            FETCH crsr INTO alias, first_name, last_name;
            CLOSE crsr;
          END;
          -- build a response header
          -- based on the pieces from the request header
          SET authinfo = 
            XMLELEMENT( 'Authentication',
              XMLATTRIBUTES(
                namespace as xmlns,
                alias,
                mustUnderstand ),
                XMLELEMENT( 'first', first_name ),
                XMLELEMENT( 'last', last_name ) );
          CALL SA_SET_SOAP_HEADER( 'authinfo', authinfo );
        END IF;
      END LOOP header_loop;
      SELECT ROUND((temperature - 32.0) * 5.0 / 9.0, 5) 
      AS answer;
    END;

可将 NEXT_SOAP_HEADER 和 SOAP_HEADER 函数结合使用来获得 SOAP 请求中的标头。NEXT_SOAP_HEADER 函数将遍历包含在请求中的 SOAP 标头并返回下一个 SOAP 标头名。如果用 NULL 调用该函数,该函数会返回第一个标头的名称。通过向 NEXT_SOAP_HEADER 函数传递上一个标头的名称来检索后续的标头。当用最后一个标头的名称调用该函数时,该函数返回 NULL。在该示例中执行 SOAP 标头检索的 SQL 代码如下所示。它会在最后返回 NULL 时退出循环。

SET hd_key = NEXT_SOAP_HEADER( hd_key );
    IF hd_key IS NULL THEN
      -- no more header entries
      LEAVE header_loop;
    END IF;

重复调用该函数将会返回所有的标头字段且仅返回一次,但不一定与其出现在 SOAP 请求中的顺序相同。

SOAP_HEADER 函数将返回指定的 SOAP 标头字段的值或 NULL(如果不是从 SOAP 服务调用)。当通过 Web 服务处理 SOAP 请求时,将使用该函数。如果给定字段名的标头不存在,则会返回值 NULL。

该示例将搜索名为 Authentication 的 SOAP 标头。当它找到此标头时,便会抽取整个 SOAP 标头的值以及 [@namespace] 和 [mustUnderstand] 属性的值。SOAP 标头值可能类似于下面的 XML 字符串:

<Authentication xmlns="SecretAgent" mustUnderstand="1">
  <userName alias="99">
    <first>Susan</first>
    <last>Hilton</last>
  </userName>
</Authentication>

对于此标头,[@namespace] 属性值将为:[SecretAgent]

同时,[mustUnderstand] 属性值将为:1

使用设置为 /*:Authentication/*:userName 的 XPath 字符串来通过 OPENXML 函数分析此 XML 字符串的内部。

SELECT * 
FROM OPENXML( hd_entry, xpath )
  WITH ( alias LONG VARCHAR '@*:alias',
  first_name LONG VARCHAR '*:first/text()',
  last_name LONG VARCHAR '*:last/text()' );

通过使用上面所示的示例 SOAP 标头值,SELECT 语句将会创建一个如下所示的结果集:

alias first_name last_name
99 Susan Hilton

在此结果集上会声明一个游标,且会将三个列值读取到三个变量中。此时,您获取了传递给 Web 服务的所有相关信息。您获取了华氏温度值以及一些通过 SOAP 标头传递给 Web 服务的其它属性。那么您要如何处理这些信息?

您可以检查所提供的名称和别名,以确定此人是否已被授权使用该 Web 服务。但此步骤并未在示例中表明。

存储过程中的下一步是以 SOAP 格式创建一个响应。可以按如下所示构建该 XML 响应:

SET authinfo = 
  XMLELEMENT( 'Authentication',
    XMLATTRIBUTES(
      namespace as xmlns,
      alias,
      mustUnderstand ),
      XMLELEMENT( 'first', first_name ),
      XMLELEMENT( 'last', last_name ) );

这样会构建出以下 XML 字符串:

<Authentication xmlns="SecretAgent" alias="99" 
                            mustUnderstand="1">
  <first>Susan</first>
  <last>Hilton</last>
</Authentication>

最后,为将 SOAP 响应返回到调用方,使用 SA_SET_SOAP_HEADER 存储过程:

CALL SA_SET_SOAP_HEADER( 'authinfo', authinfo );

与上一节的示例相同,最后一步是执行从华氏度转换到摄氏度的计算。

此时,您已经有一个运行的 SQL Anywhere Web 服务服务器可将温度从华氏度转换为摄氏度,这与上一节相同。但主要区别是,它还可以处理来自调用方的 SOAP 标头并将 SOAP 响应发送回调用方。

这仅是整个过程的一半。下一步是开发一个可发送 SOAP 请求并接收 SOAP 响应的示例客户端。

如果您已执行上一节中概述的步骤,则可以跳过第 1 步到第 3 步,直接进行第 4 步。

♦  发送和接收 SOAP 标头
  1. 创建另一个数据库以供与第二台服务器一同使用。

    dbinit ftc_client
  2. 使用此数据库启动个人服务器。

    dbeng11 ftc_client.db
  3. 使用另一个 Interactive SQL 实例连接到个人服务器。

    dbisql -c "UID=DBA;PWD=sql;ENG=ftc_client"
  4. 使用 Interactive SQL 创建一个存储过程。

    CREATE PROCEDURE FtoC( temperature FLOAT,
        INOUT inoutheader LONG VARCHAR,
        IN inheader LONG VARCHAR )
      URL 'http://localhost:8082/FtoCService'
      TYPE 'SOAP:DOC'
      SOAPHEADER '!inoutheader!inheader';

    该 URL 子句用于引用 SOAP Web 服务。字符串 ['http://localhost:8082/FtoCService'] 用于指定要使用的 Web 服务的 URI。这是对监听端口 8082 的 Web 服务器的引用。

    发出 Web 服务请求时使用的缺省格式是 'SOAP:RPC'。此示例中选择的格式为 'SOAP:DOC',此格式与 'SOAP:RPC' 类似,但是它允许使用更丰富的一组数据类型。SOAP 请求始终作为 XML 文档发送。发送 SOAP 请求所用的机制是 'HTTP:POST'。

    SQL Anywhere 客户端过程中的替代变量(inoutheader、inheader)必须是字母数字。如果 Web 服务客户端被声明为函数,则其所有参数都只能是 IN 模式(它们不能由被调用函数赋值)。因此,必须使用 OPENXML 或其它字符串函数抽取 SOAP 响应标头信息。

  5. 您需要一个用于 FtoC 存储过程的包装,因此按如下所示创建另一个存储过程。与上一节中的示例不同,此示例包含其它语句,用于创建特殊 SOAP 标头、在 Web 服务调用中将其发送,以及处理来自 Web 服务器的响应。如果您已完成了上一节中的示例,则将下面的 CREATE 更改为 ALTER,因为您现在要修改该存储过程。

    CREATE PROCEDURE FahrenheitToCelsius( temperature FLOAT )
    BEGIN
      DECLARE io_header LONG VARCHAR;
      DECLARE in_header LONG VARCHAR;
      DECLARE result LONG VARCHAR;
      DECLARE err INTEGER;
      DECLARE crsr CURSOR FOR
        CALL FtoC( temperature, io_header, in_header );
      SET io_header =
        '<Authentication xmlns="SecretAgent" ' ||
                         'mustUnderstand="1">' ||
        '<userName alias="99">' ||
        '<first>Susan</first><last>Hilton</last>' ||
        '</userName>' ||
        '</Authentication>';
      SET in_header =
        '<Session xmlns="SomeSession">' ||
        '123456789' ||
        '</Session>';
    
      MESSAGE 'send, soapheader=' || io_header || in_header;
      OPEN crsr;
      FETCH crsr INTO result, err;
      CLOSE crsr;
      MESSAGE 'receive, soapheader=' || io_header;
      SELECT temperature, Celsius
      FROM OPENXML(result, '//tns:answer', 1, result)
             WITH ("Celsius" FLOAT 'text()');
    END;

    此存储过程充当对 Web 服务的调用的包装过程。此存储过程的功能已在上一节的示例基础上得到了增强。它创建两个 SOAP 标头。第一个 SOAP 标头如下所示。

    <Authentication xmlns="SecretAgent" 
                                mustUnderstand="1">
      <userName alias="99">
        <first>Susan</first>
        <last>Hilton</last>
      </userName></Authentication>

    第二个 SOAP 标头如下所示。

    <Session xmlns="SomeSession">123456789</Session>

    打开游标时,会将 SOAP 请求发送到 Web 服务。

    <Authentication xmlns="SecretAgent" alias="99" 
                                mustUnderstand="1">
    <first>Susan</first>
    <last>Hilton</last>
    </Authentication>

    FtoC 存储过程返回一个此存储过程将处理的结果集。该结果集如下所示。

    <tns:rowset xmlns:tns="http://localhost/ftc/FtoCService">
     <tns:row>
      <tns:answer>100</tns:answer>
     </tns:row>
    </tns:rowset>

    OPENXML 函数用于分析返回的 XML,从而抽取摄氏温度值。

  6. 调用该存储过程以发送请求并获得响应:

    CALL FahrenheitToCelsius(212);

    将出现华氏温度和对等的摄氏温度。

    温度 摄氏
    212.0 100.0

可将 SQL Anywhere Web 服务客户端声明为函数或者过程。SQL Anywhere 客户端函数声明会将所有参数都有效限定于 in 模式(参数不能由被调用函数赋值)。调用 SQL Anywhere Web 服务函数将返回原始 SOAP 封装响应,而某过程会返回一个结果集。

SOAPHEADER 子句已被添加到 create/alter procedure/function 语句。SOAP 标头可声明为静态常量,也可使用参数替代机制进行动态设置。Web 服务客户端函数可定义一个或多个 in 模式替代参数,而 Web 服务客户端过程也可定义一个 inout 或 out 替代参数。因此,Web 服务客户端过程可返回 out(或 inout)替代参数中的响应 SOAP 标头。Web 服务函数必须分析响应 SOAP 封装以获得标头条目。

以下示例说明客户端如何指定发送多个带有参数的标头条目和接收响应 SOAP 标头数据。

CREATE PROCEDURE SoapClient( 
    INOUT hd1 VARCHAR, 
    IN hd2 VARCHAR, 
    IN hd3 VARCHAR ) 
  URL 'localhost/some_endpoint' 
  SOAPHEADER '!hd1!hd2!hd3';
注意
限制