2

通过在响应标头中添加“Set-Cookie”属性,我设法在 WCF 服务传出响应中添加了多个 cookie。它工作得很好,只有当有一个 cookie 而不是多个 cookie 时,cookie 才可在所有后续请求中使用。请参考我下面的实现。我通过实现 IDispatchMessageInspector 接口将 cookie 添加到响应标头中,以便在响应中更新任何挂起的 cookie 时在所有 WCF 服务方法调用中添加 cookie。

响应标头和请求标头中的 Cookie 输出示例

1 饼干: foo=testcookie1; path=/ --> 在所有后续请求调用中可用 2 个或更多 cookie:foo=testcookie1; 路径=/;, foo2=testcookie2; 路径=/;, foo3=testcookie3; 路径=/; --> --> 仅在所有后续请求调用中可用的第一个 cookie,但在其他请求中不可用

例如:

设置 cookie 后,我的响应标头将类似于Set-Cookie: foo1=testcookie1;,foo2=testcookie2;, foo3=testcookie3; . 如果我发出另一个请求,则请求标头 cookie 仅包含foo1=testcookie1; 但不是这些 cookie foo2=testcookie2; foo3=testcookie3; . 这就是问题所在。如果我在响应标头中设置了多个 cookie,那么在后续请求调用中它总是只使用第一个 cookie。

请帮我解决这个问题。提前感谢您的友好回复。


执行

public class CookieManagerServiceBehaviorAttribute : Attribute, IServiceBehavior
{
    #region IServiceBehavior Members
    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
        return;
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcher channelDispatch in serviceHostBase.ChannelDispatchers)
        {
            foreach (EndpointDispatcher endpointDispatch in channelDispatch.Endpoints)
            {
                endpointDispatch.DispatchRuntime.MessageInspectors.Add(CookieManagerMessageInspector.Instance);
            }
        }
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        return;
    }
    #endregion
}

public class CookieManagerMessageInspector : IDispatchMessageInspector
{
    private static CookieManagerMessageInspector instance;
    private CookieManagerMessageInspector() { }
    public static CookieManagerMessageInspector Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new CookieManagerMessageInspector();
            }
            return instance;
        }
    }

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        HttpResponseMessageProperty httpResponse;
        if (!reply.Properties.ContainsKey(HttpResponseMessageProperty.Name))
        {
            reply.Properties.Add(HttpResponseMessageProperty.Name, new HttpResponseMessageProperty());
        }
        httpResponse = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
        foreach (Cookie cookie in RenderContext.Current.PendingCookies)
        {
            if (cookie.Expires > DateTime.Now)
                httpResponse.Headers.Add(HttpResponseHeader.SetCookie, "{0}={1}; expires={2}".StringFormat(cookie.Name, cookie.Value, DateTime.Now.AddYears(1).ToUniversalTime()) + ";");
            else
                httpResponse.Headers.Add(HttpResponseHeader.SetCookie, "{0}={1};".StringFormat(cookie.Name, cookie.Value));
        }
    }
}
4

1 回答 1

3

在构建网络代理时,我遇到了同样的问题。我需要将 Set-Cookie 标头从目标 HttpWebResponse 中继到代理 HttpListenerResponse。如果 Set-Cookie 标头中有多个 cookie,则只有第一个会在浏览器中注册。

当我遍历标头的一组值(或者在您的情况下是 Cookie 的集合)并使用 response.AppendHeader(header, value) 表单时,我能够让它工作。

string[] cookies = response.Headers.GetValues("Set-Cookie");
foreach (string value in cookies)
    clientResponse.AppendHeader("Set-Cookie", value);

因此,在您的情况下,我会将代码的结尾更改为:

if (cookie.Expires > DateTime.Now)
     httpResponse.AppendHeader(HttpResponseHeader.SetCookie, "{0}={1}; expires={2}".StringFormat(cookie.Name, cookie.Value, DateTime.Now.AddYears(1).ToUniversalTime()) + ";");
else
     httpResponse.AppendHeader(HttpResponseHeader.SetCookie, "{0}={1};".StringFormat(cookie.Name, cookie.Value));
于 2011-10-20T02:28:51.510 回答