WCF发出消息时的Content-Length HTTP标头

3
我遇到了一个棘手的问题,我的Java Web服务端点托管在IBM HTTP服务器(IHS)上,虽然它应该符合HTTP/1.1标准,但需要Content-Length头。如果我发送这个头,一切都正常。如果我省略它,我会收到500错误响应,告诉我我的POST实体主体是空的(尽管不是空的)。
我们已经为这些服务投入了大量时间(由第三方开发),但我似乎找不到一种好的方法来追加Content-Length头到请求中。我能够使用IClientMessageInspector添加任意头部(例如X-Dan-Lynn-Header)到请求中,如这篇博客所述,但WCF似乎忽略Content-Length头。
我的选择是:
a) 弄清楚如何强制WCF将Content-Length头追加到HTTP POST请求中或,
b) 找到或编写一个极其简单透明的HTTP代理,用Content-Length头装饰请求。
谢谢!
示例:IClientMessageInspector.BeforeSendRequest

public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
    var buffer = request.CreateBufferedCopy(Int32.MaxValue);
    var tempRequest = buffer.CreateMessage();


    HttpRequestMessageProperty httpRequest = GetHttpRequestProp(tempRequest);
    if (httpRequest != null)
    {
        if (string.IsNullOrEmpty(httpRequest.Headers[HttpRequestHeader.ContentLength]))
        {
            httpRequest.Headers.Add(HttpRequestHeader.ContentLength, GetMessageLength(buffer).ToString());
            httpRequest.Headers.Add("X-Dan-Lynn-Header", "abcdefghijk");
        }

    }

    request = tempRequest;
    request.Properties[HttpRequestMessageProperty.Name] = httpRequest;

    return null;
}

WCF生成的示例请求(以及前面的IClientMessageInspector):

POST /path/to/service HTTP/1.1
Content-Type: text/xml; charset=utf-8
X-Dan-Lynn-Header: abcdefghijk
SOAPAction: "http://tempuri.org/path/to/service/action"
Host: service.host.tld
Transfer-Encoding: chunked
Connection: Keep-Alive


<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        .......body removed for clarity......

    </s:Body>
</s:Envelope>

1
它是否使用了不同的头部,比如“Transfer-Encoding: chunked”之类的?缺少Content-Length头可能表明您正在流式传输请求等。 - Andy White
也许是分块头部引起了问题。我会进行调查并报告。 - Dan Lynn
3个回答

5

搞定了。设置绑定使用transferMode="Streamed"会导致Transfer-Encoding:chunked。由于Web服务响应非常大,我们需要流式传输,因此我能够选择:

不好的:

transferMode="Streamed"

好的:

transferMode="StreamedResponse"

将绑定更改为this解决了问题:

<basicHttpBinding>
    <binding name="MyBinding" closeTimeout="00:30:00" openTimeout="00:30:00"
      receiveTimeout="00:30:00" sendTimeout="00:30:00" allowCookies="false"
      bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
      maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="16777216"
      messageEncoding="Text" textEncoding="utf-8" transferMode="StreamedResponse"
      useDefaultWebProxy="false">
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="65536"
        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      <security mode="None" />
    </binding>
  </basicHttpBinding>

谢谢分享你的解决方案 - 但是你能解释一下你改变了这个绑定的什么吗?你改成了“basicHttpBinding”吗?从哪里改变的?我只是想记录这些东西,以便其他可能遇到相同(或类似)问题的人可以参考! - marc_s
我一开始使用的是basicHttpBinding,但之前它被设置为transferMode="Streamed"。这会导致绑定将请求和响应都视为流式传输(也称为分块)。IBM HTTP服务器配置对分块的传输编码抛出了错误。 - Dan Lynn

1

我目前无法实际运行代码以查看发生了什么,但类似于

WCFClient client = new WCFClient();
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))    
{     
    HttpRequestMessageProperty req = new HttpRequestMessageProperty();            
    req.Headers.Add("Content-Length", "YOUR CONTENT LENGTH HERE");      
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = req;      
}

请参阅http://msdn.microsoft.com/en-us/library/aa395196.aspx,了解如何使用OperationContextScope对象包含其他标头的更多信息。

更新: 我必须说我觉得这是一个奇怪的问题。我想知道为什么内容长度没有被设置。如果您的实际问题在其他地方,我不会感到惊讶。


0

在app.config中设置transferMode=StreamedResponse也对我解决了类似于你遇到的问题。 我使用WCF架构进行同步框架和Squid代理3.1.20,但Streamed transferMode不被支持。 非常感谢!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接