2011-08-23 54 views
2

问题: DataServiceContext.SaveChanges()以“302 - 移动”响应失败。WCF数据服务错误 - 302在与HTTPS + Load Balancer相关的SaveChanges()上移动?

背景/可疑原因:负载平衡器! - 我们最近更改了基础设施,以便我们的Web服务器现在位于负载均衡器的后面,该负载均衡器也处理ssl。客户将服务定位为HTTPS,但由于SSL是由负载均衡器完成的(我相信大多数人都熟悉这种类型的设置),IIS最终会处理HTTP请求。无论如何,我们最终得到的是包含使用HTTP而不是HTTPS的URI的提要。 (请参阅http请求中的GET请求/响应,而不是httpS)。该行为是非常奇怪的,因为当我打电话调用SaveChanges()发送一个MERGE(如预期),我拿回302:

HTTP/1.1 302 Object moved 
Location: https://some.domain.org/CMSProfileService/ProfileDataService.svc/Mails(guid'80fef993-a4b5-4343-a908-28c2c6517a81') 
Connection: close 

但WCF一直在尝试MERGE,并使用HTTP(约50时间),然后最后抛出一个异常与消息,“”处理此请求时发生错误。“,内部excepion消息是”找到“。:)

当我直接指向服务器(绕过loadbalancer和ssl )一切工作正常。当SSL直接在IIS中注册时,一切都可以正常工作。

必须有一些配置设置/属性,我是没有找到。 Viteks answer到一个类似的问题吓了我一下。

这是从提琴手

GET https://some.domain.org/CMSProfileService2/ProfileDataService.svc/Mails()?$filter=Status%20eq%20'Queued'&$orderby=Timestamp&$expand=Attachments HTTP/1.1 
User-Agent: Microsoft ADO.NET Data Services 
DataServiceVersion: 1.0;NetFx 
MaxDataServiceVersion: 2.0;NetFx 
UserName: 
Accept: application/atom+xml,application/xml 
Accept-Charset: UTF-8 
Host: some.domain.org 
Connection: Keep-Alive 

和这里的原始GET请求的原始响应(修整):

HTTP/1.1 200 OK 
Set-Cookie: ARPT=RPZVOOS192.168.94.118CKOUM; path=/ 
Cache-Control: no-cache 
Content-Length: 45849 
Content-Type: application/atom+xml;charset=utf-8 
Server: Microsoft-IIS/7.5 
DataServiceVersion: 1.0; 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 
Date: Mon, 22 Aug 2011 14:56:46 GMT 

<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<feed xml:base="http://some.domain.org/CMSPRofileService2/ProfileDataService.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom"> 
    <title type="text">Mails</title> 
    <id>http://some.domain.org/CMSProfileService2/ProfileDataService.svc/Mails</id> 
    <updated>2011-08-22T14:56:47Z</updated> 
    <link rel="self" title="Mails" href="Mails" /> 
    <entry> 
    <id>http://some.domain.org/CMSPRofileService2/ProfileDataService.svc/Mails(guid'c7edb158-7a61-4fca-a40e-7f4a3a0b2bbd')</id> 
    <title type="text"></title> 
    <updated>2011-08-22T14:56:47Z</updated> 
    <author> 
     <name /> 
    </author> 
    <link rel="edit" title="Mail" href="Mails(guid'c7edb158-7a61-4fca-a40e-7f4a3a0b2bbd')" /> 
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Attachments" type="application/atom+xml;type=feed" title="Attachments" href="Mails(guid'c7edb158-7a61-4fca-a40e-7f4a3a0b2bbd')/Attachments"> 
     <m:inline> 
     <feed> 
      <title type="text">Attachments</title> 
      <id>http://some.domain.org/CMSPRofileService2/ProfileDataService.svc/Mails(guid'c7edb158-7a61-4fca-a40e-7f4a3a0b2bbd')/Attachments</id> 
      <updated>2011-08-22T14:56:47Z</updated> 
      <author> 
      <name /> 
      </author> 
      <link rel="self" title="Attachments" href="Mails(guid'c7edb158-7a61-4fca-a40e-7f4a3a0b2bbd')/Attachments" /> 
     </feed> 
     </m:inline> 
    </link> 
    <category term="XXX.YYY.Profile.Repository.Mail" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
    <content type="application/xml"> 
     <m:properties> 
     <d:MailId m:type="Edm.Guid">c7edb158-7a61-4fca-a40e-7f4a3a0b2bbd</d:MailId> 
     <d:Timestamp m:type="Edm.DateTime">2011-07-28T12:51:37.69</d:Timestamp> 
     <d:ApplicationCode>EREF</d:ApplicationCode> 
     <d:Status>Queued</d:Status 
. 
. 
. 
+0

Vitek,你在哪里人! ;) – Dan

+0

你正在使用什么样的负载均衡器?负载均衡器中有任何配置吗? –

+0

它是一个较老的cisco(〜5岁)负载均衡器,不确定型号的确切数据,我将在此处检查并发布信息 – Dan

回答

0

终于解决了这个讨厌的问题。其实有两个问题。

问题#1:在负载均衡器中使用https托管在IIS中的WCF数据服务使用http URI而不是https创建提要。这是可以理解的,是我对这个问题的第一次猜测。通过大量的挖掘,我遇到了this文章,它提供了一个非常简单的解决方案。

在我服务的构造函数我挂接到处理请求事件

ProcessingPipeline.ProcessingRequest += ProcessingPipeline_ProcessingRequest; 

在事件处理程序,我用提到的文章,并取得了一定的调整,基本上采取的主机,方案和端口从clientExpectsUri并将它们应用于请求Uri。我也只是寻找一个自定义标题,我称之为“X-Client-Expects-RootUri”,防火墙外的客户端需要发送,如果他们想要有效的提要。

static void ProcessingPipeline_ProcessingRequest(object sender, DataServiceProcessingPipelineEventArgs e) 
{ 
    if (e.OperationContext.RequestHeaders.AllKeys.Contains(ClientExpectsUriKey)) 
     ProcessUri(new Uri(e.OperationContext.RequestHeaders[ClientExpectsUriKey]));  
} 

private static void ProcessUri(Uri clientExpectsRootUri) 
{ 
    if (clientExpectsRootUri != null) 
    { 
     var requestUri = OperationContext.Current.IncomingMessageProperties.ContainsKey("MicrosoftDataServicesRequestUri") 
           ? OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] as Uri : HttpContext.Current.Request.Url; 

     var serviceUri = clientExpectsRootUri; 

     var serviceUriBuilder = new UriBuilder(serviceUri); 

     var requestUriBuilder = new UriBuilder(requestUri) 
            { 
             Host = serviceUriBuilder.Host, 
             Scheme = serviceUriBuilder.Scheme, 
             Port = serviceUriBuilder.Port 
            }; 

     if (!serviceUriBuilder.Path.EndsWith("/")) //the base uri should end with a slash... 
      serviceUriBuilder.Path = serviceUriBuilder.Path += "/"; 

     OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = serviceUriBuilder.Uri; 
     OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = requestUriBuilder.Uri; 
    } 
} 

我真的喜欢上了这设计的一些反馈意见,因为我基本上是要求客户告诉我如何通过自定义标题返回URI。我将在未来考虑修改负载平衡器以自动添加这些标头。

问题#2:没有为MERGE和其他非RFC http方法配置负载平衡器。此问题的解决方案非常简单,只需在DataServiceContext上将usePostTunneling设置为true即可。如果任何人有脚本来为思科11503启用非RFC的http方法,我很乐意拥有它们。 ;-)

2

这里的问题是可能的self/links编辑链接是HTTP,而不是HTTPS,因此客户端无法使用链接访问数据。每Vitek的scary answer

不幸的是服务器不知道它在哪里。

我能想到几个选项(他们都没有特别好的)的:

  1. 使用,它告诉数据服务它的根是HTTPS定制IDataServiceHost2:// ...通过AbsoluteServiceUri财产。这样数据服务应该产生适当的URLS
  2. 实现一个WCF行为,删除http:// url并用https://替换它们,这将涉及很多缓冲等。检出这个JSONP example哪些修改了来自服务器的响应。

-Alex

+0

是的,这是我的想法。有没有HTTP标头,我可以配置负载均衡器发送WCF可以评估并确定他在代理后面运行?无论如何,我会尝试实施IDataServiceHost2并回来。 – Dan

+0

如果您使用在IIS中托管时使用的标准DataServiceHost,我不认为您可以执行任何操作。 –

+0

好的,我有一个更新,我在这里发现了另一篇文章http://blogs.msdn.com/b/peter_qian/archive/2010/03/24/overwriting-the-service-root-uri-in-wcf-data -service.aspx看起来很有前途,现在我的feed看起来很完美(到处都是https uris),但是我得到了完全相同的行为(302响应)。看起来这应该现在工作,但它不是,所以明天我想我会实现IDataServiceHost2,但我有一种感觉,我最终会遇到同样的问题。 – Dan