1

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

我找到了一个讨论它的页面(http://bytes.com/forum/thread160816.html)并将代码实现为测试。我构建了一个小型 .NET 应用程序,它使用 Web 服务并调用每个函数并显示结果。根据我的阅读,只要使用 setClass() 函数将功能封装在一个类中,并且 setPersistence() 函数通过 SOAP_PERSISTENCE_SESSION 传递,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——如果有人有更好的方法来做到这一点,我愿意接受建议;但是,我仍然想解决一般情况。有人有想法么?

4

3 回答 3

1

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

我的工作假设是: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();
        }
    }
}

不管怎么说,还是要谢谢你!

于 2008-11-18T00:59:56.783 回答
0

大多数soap客户端为每个请求启动一个新连接,因此没有“会话”。

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

这要好得多,因为您的客户现在对行为有了线索和控制权。

于 2008-11-17T16:19:03.777 回答
0

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

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

现在$headers必须包含名称类似于“ASP.NET_SessionId”的会话 ID。从 中获取 ID$headers并创建一个 cookie,如下所示:

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

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

于 2012-04-13T10:27:15.583 回答