问题: DataServiceContext.SaveChanges()失败并显示“302 - 移动”响应。
背景/可疑原因:负载均衡器! - 我们最近更改了基础架构,以便我们的Web服务器现在位于负载均衡器后面,负载均衡器也可以处理ssl。客户端将服务称为HTTPS,但IIS最终处理HTTP请求,因为SSL由负载均衡器完成(我相信大多数人都熟悉这种类型的设置)。无论如何,我们最终得到的是包含使用HTTP而不是HTTPS的URI的订阅源。 (请参阅下面的GET请求/响应,在响应中使用http而不是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一直在使用HTTP(大约50次)反复尝试MERGE,然后最终抛出异常消息,“”处理此请求时出错。“,内部异常消息是”Found“。:)
当我直接指向服务器(绕过负载均衡器和ssl)时,一切正常。当SSL直接在IIS中注册时,一切也正常。
必须有一些我找不到的配置设置/属性。 Viteks answer对类似的问题让我感到有些害怕。
这是来自fiddler的原始GET请求
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
,这是原始响应(修剪):
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 :(得分:2)
此处的问题可能是自我/链接编辑链接是HTTP,而不是HTTPS,因此客户端无法使用链接访问数据。 Per Vitek的scary answer。
不幸的是服务器不知道它在哪里。
我可以想到几个选项(它们都不是特别好):
AbsoluteServiceUri
属性告知数据服务其根目录是https:// ....这样数据服务应该生成适当的URL -Alex
答案 1 :(得分: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即可。如果有人有脚本为cisco 11503启用非RFC http方法,我很乐意拥有它们。 ; - )