我正在尝试使用SOAP扩展在PHP中实现有状态的Web服务。 (是的,我知道Web服务应该是无状态的;我真正关心的只是某种形式的会话ID,因此我不需要对每次调用服务进行身份验证)。 PHP.net的API文档在这方面有些缺乏,并且没有其他内容写在上面。
我找到了一个讨论它的页面(http://bytes.com/forum/thread160816.html)并将代码实现为测试。我构建了一个小型.NET应用程序,它使用Web服务并调用每个函数并显示结果。根据我的阅读,PHP SOAP扩展将在调用之间保持类变量,只要使用setClass()函数将函数封装在类中并且传递了setPersistence()函数SOAP_PERSISTENCE_SESSION。
这是我的代码:
<?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 - 如果有人有更好的方法来执行此操作,我会接受建议;但是,我仍然想解决一般情况。有人有什么想法吗?
答案 0 :(得分: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();
}
}
}
非常感谢!
答案 1 :(得分:0)
大多数soap客户端为每个请求启动一个新连接,因此没有“会话”。
如果是您的SOAP服务,您可以在每个回复的SOAP信封内部的某处发送会话ID,并要求客户端在每个后续请求中传递会话ID。
这更好,因为您的客户现在有线索和控制beheaviour。
答案 2 :(得分:0)
要使用有状态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。从$headers
获取ID并创建一个cookie,如下所示:
//$client->__setCookie($cookieName, $cookieValue);
$client->__setCookie('ASP.NET_SessionId', $cookieValue);
现在,来自客户端的所有SOAP请求都将包含此会话ID,您的状态将保留在服务器上。