我正在尝试使用SOAP扩展在PHP中实现有状态的Web服务。 (是的,我知道Web服务应该是无状态的;我真正关心的只是某种形式的会话ID,因此我不需要对每次调用服务进行身份验证)。 PHP.net的API文档在这方面有些缺乏,并且没有其他内容写在上面。

我找到了一个讨论它的页面( http://bytes.com/forum/thread160816.html )并将代码实现为测试。我构建了一个小型.NET应用程序,它使用Web服务并调用每个函数并显示结果。根据我的阅读,只要使用setClass()函数将函数封装在类中并且传递了SOAPPERSISTENCE_SESSION的setPersistence()函数,PHP SOAP扩展将在调用之间保持类变量。

这是我的代码:

<?php

class User 
{
    var $name = "Initial value";

    function setName($name) 
    {
        $this->name = $name;

        // Tried this too.
        // $this->name = "Set to string constant" ;
    }

    function getName() 
    {
        // This always returns "Initial value"
        return $this->name;
    }
}


// Tried placing session_start() in several places
// before $server->handle()...
// One guy says this doesn't need to be called.
// I assume it depends on if session autostart is on.
session_start();

$server = new SoapServer(null, array('uri' => 'http://localhost/'));
$server->setClass('User');
$server->setPersistence(SOAP_PERSISTENCE_SESSION);
$server->handle();

?>

我遇到的问题是$ name在调用之间没有持久化 - 我总是得到初始值而不是我赋给setName()的值。正如我所说的那样,我试图在对数据库进行身份验证后保留会话ID - 如果有人有更好的方法来执行此操作,我会接受建议;但是,我仍然想解决一般情况。有人有什么想法吗?

有帮助吗?

解决方案

我实际上解决了自己的问题。

我的工作假设是:1).NET自动处理cookie; 2)我的问题是PHP。情况也不是这样。我的PHP代码很好,但我需要在我的.NET代码中添加一个元素来处理会话cookie。

在实例化Web服务对象之后,我需要将一个CookieContainer类的实例分配给Web服务对象。我的最终客户端代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WsTest
{
    public partial class PhpWsForm : Form
    {
        private localhost.MyWebService ws;

        public PhpWsForm()
        {
            InitializeComponent();
            ws = new WsTest.localhost.MyWebService();

            // The line below is the part that I forgot!
            ws.CookieContainer = new System.Net.CookieContainer();
        }

        private void butSetVal_Click(object sender, EventArgs e)
        {
            ws.setName(txtSetVal.Text);
        }

        private void butGetVal_Click(object sender, EventArgs e)
        {
            txtGetVal.Text = ws.getName();
        }
    }
}

非常感谢!

其他提示

大多数soap客户端为每个请求启动一个新连接,因此没有<!> quot; session <!>;。

如果是您的SOAP服务,您可以在每个回复的SOAP信封内部的某处发送会话ID,并要求客户端在每个后续请求中传递会话ID。

这更好,因为您的客户现在有线索和控制beheaviour。

要使用有状态Web服务,您需要在客户端的SOAP cookie中设置服务器会话的会话ID。默认情况下,每次发送SOAP请求时,服务器都会生成唯一的会话ID。为了防止这种情况,只需在SOAP cookie中设置第一个请求获得的会话ID。该cookie将与您随后的所有肥皂调用一起发送。 举个例子,如果你使用SOAP消费ASP.net webservice,那么在第一次WS调用之后,得到这样的响应头:

$client = SoapClient("some.wsdl", array('trace' => 1));
$result = $client->SomeFunction();
$headers = $client->__getLastResponseHeaders();

现在$headers必须包含名称为“ASP.NET_SessionId”的会话ID。从<=>获取ID并创建cookie,如下所示:

//$client->__setCookie($cookieName, $cookieValue);
$client->__setCookie('ASP.NET_SessionId', $cookieValue);

现在,来自客户端的所有SOAP请求都将包含此会话ID,您的状态将保留在服务器上。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top