duancan1900 2018-09-25 20:08
浏览 77

如何使用Savon Gem使用PHP to Rails调用SOAP wsdl API

I have to port code from a PHP app calling a WSDL API to Rails

here is my PHP code:

class naf
{
    protected $_soap;
    protected $_token = array('Token' => '');
    protected $_header;

    public function __construct()
    {
        $this->_soap = new SoapClient('http://apiwebsite/api.asmx?WSDL', array('trace' => true));
        $this->_header = new SoapHeader('http://apinamespace/api/', 'Authenticationtoken', $this->_token, true);
    }

    public static function forge() {
        return new static;
    }

    public function get_boards()
    {
        $result = $this->_makeCall('getBoardList', array());
        return $result->getBoardListResult->BoardList;
    }

    public function board_list() {
        $data = array();
        $result = $this->get_boards();
        foreach ($result as $row) {
            $data[$row->Boardid] = $row->LongName;
        }
        return $data;
    }

    public function login($id, $passwrd, $board)
    {
        $args = array('userid' => $id, 'password' => $passwrd, 'board' => $board);
        return $this->_makeCall('login', $args);
    }

    public function logoff($id, $sid)
    {
        $args = array('creaid' => $id, 'sessionid' => $sid);
        return $this->_makeCall('logoff', $args);
    }

    public function isLogin($id, $sid)
    {
        $args = array('creaid' => $id, 'sessionid' => $sid);
        return $this->_makeCall('isAuthenticated', $args);
    }

    protected function _makeCall($action, $args)
    {
        try {
            $result = $this->_soap->__soapCall($action, $args, null, $this->_header, $outHeaders);
            return $result;
        } catch (Exception $e) {
            error_log(print_r($e, true));
        }
    }
}

I tried a Lot of things with "Savon" but it seems that my header is never set. I even port it successfully to C#, but the SoapHeader always seem wrong in rails. I always get

ERROR: (soap:clientfault) System.Web.Services.Protocols.SoapException: Empty tokenid

It seems it can't see my header

P.S. The Token parameter is voluntary ommit in the code below

Here is my rail code:

require 'savon'

class Naf

  NAF_API_TOKEN = { Token: ''}

  def initialize()
    @wsdl = 'http://apiwebsite/api.asmx?WSDL'
    @header = { :Authenticationtoken => NAF_API_TOKEN }
  end

  def get_boards()
    puts "=========== Naf.get_boards ================== "

    result = makeCall(:get_board_list, {})

    return result.getBoardListResult.BoardList
  end

  def board_list()
    data = Array.new()
    results = get_boards()

    results.each do | row |
      data[row.Boardid] = row.LongName
    end

    return data

  end

  def login(id, passwrd, board)
    args = {:userid => id, :password => passwrd, :board => board}
    makeCall('logoff', args)
  end

  def logoff(id, sid)
    args = {:creaid => id, :sessionid => sid}
    makeCall('logoff', args)
  end

  def isLogin(id, sid)
    args = {:creaid => id, :sessionid => sid}
    makeCall('isAuthenticated', args)
  end

  private
  def makeCall(action, args)
    puts "=========== Naf.makeCall ================== "
    begin

      client = Savon.client(
          wsdl: @wsdl,
          soap_header: @header
          )
      return client.call(action, args)

    rescue Exception => e
      puts "ERROR: #{e.message}"
    end
  end

end

I just got the expect XML request:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://apinamespace/api/">
   <SOAP-ENV:Header>
      <ns1:Authenticationtoken SOAP-ENV:mustUnderstand="1">
         <ns1:Token>TOKENHERE</ns1:Token>
      </ns1:Authenticationtoken>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body>
      <ns1:getBoardList />
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
  • 写回答

1条回答 默认 最新

  • ds11111111111111111 2018-09-26 13:10
    关注

    Im not sure if I did it the best way but I got it working:

    I had to add a namespace definition and had to tweak the header to add my own "tag prefix" like that:

    NAF_API_TOKEN = { 'tns:Token' => 'TOKEN'}

    here is my updated code:

    require 'savon'
    
    class Naf
    
      #HACK I had to add the "TNS" keyword to make it work
      NAF_API_TOKEN = { 'tns:Token' => 'TOKEN'}
    
      def initialize()
        @wsdl = 'http://webapi/apiws/api.asmx?WSDL'
        @header = { 'tns:Authenticationtoken' => NAF_API_TOKEN }
      end
    
      def get_boards()
        puts "=========== Naf.get_boards ================== "
        result = makeCall(:get_board_list, {})
    
        resulthash = result.to_hash
        boardlist = resulthash[:get_board_list_response][:get_board_list_result][:board_list]
    
        return boardlist
      end
    
      def board_list()
        puts "=========== Naf.board_list ================== "
    
        results = get_boards()
        data = results.map { |row | {:boardid => row[:boardid], :long_name => row[:long_name]}}
    
        puts data.inspect
        return data
    
      end
    
      def login(id, passwrd, board)
        args = {:userid => id, :password => passwrd, :board => board}
        makeCall('logoff', args)
      end
    
      def logoff(id, sid)
        args = {:creaid => id, :sessionid => sid}
        makeCall('logoff', args)
      end
    
      def isLogin(id, sid)
        args = {:creaid => id, :sessionid => sid}
        makeCall('isAuthenticated', args)
      end
    
      private
      def makeCall(action, args)
        puts "=========== Naf.makeCall ================== "
        begin
    
          client = Savon.client(
              wsdl: @wsdl,
              namespace: 'http://namespace/api/', #We need that to add the "TNS" keyword
              soap_header: @header
              #log: true, pretty_print_xml: true # Uncomment to display wsdl request
              )
    
    
          return client.call(action, args)
    
        rescue Exception => e
          puts "ERROR: #{e.message}"
        end
      end
    
    end
    
    评论

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置