我尝试使用针对.NET 4的HttpWebRequest
类发送POST请求时发现了一些奇怪的行为。这可能只与我试图发送行为异常的XDocument
对象有关,或者我不理解Save()
方法和ToString()
XDocument
方法之间的区别。
调用以下内容会导致请求的ContentLength在保存到流中时针对我的特定XDocument
设置为 316 :
using(var stream = request.GetRequestStream())
{
xDoc.Save(stream, SaveOptions.DisableFormatting);
}
这导致服务器无法理解我的请求正文。使用fiddler我捕获了正在上传的XML,然后复制&将原始XML粘贴到Fiddler的作曲家窗口中。在将此请求发送到服务器后,它出人意料地做出了回应而没有问当我检查标题时,我注意到Fiddler为ContentLength计算了 313 。
我尝试了一些实验来解决这个问题,例如首先设置ContentLength值(因为我知道这个特定请求应该是什么值),但保存到流总是会导致异常,说明数据比预期的ContentLength长。最后,我决定使用此代码解决方法来对XDocument
进行字符串化,从而使HttpWebRequest
计算出正确的ContentLength:
using(var stream = request.GetRequestStream())
using(var writer = new StreamWriter(stream))
{
writer.Write(xDoc.ToString(SaveOptions.DisableFormatting));
}
以上计算 313 并允许服务器正确响应。
为什么直接保存到流与从ToString()
方法写入数据会导致HttpWebRequest
计算不同的ContentLength标头值?这是一个错误/已知问题吗?
编辑:根据要求,这是一个MCVE来说明这一点(我正在连接的程序的API非常糟糕,我为他们的混乱道歉):
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-8", "yes"),
new XElement("PVDM_HTTPINTERFACE",
new XElement("FUNCTION",
new XElement("NAME", "LoginUserEx3"),
new XElement("PARAMETERS",
new XElement("ENTITYID", 1),
new XElement("USERNAME", "testadmin"),
new XElement("PASSWORD", "12345"),
new XElement("CLIENTPINGABLE", false),
new XElement("REMOTEAUTH", false)
)
)
)
);
HttpWebRequest requestWrittenWithString = (HttpWebRequest)WebRequest.Create("http://localhost");
requestWrittenWithString.Method = "POST";
HttpWebRequest requestWrittenWithSave = (HttpWebRequest)WebRequest.Create("http://localhost");
requestWrittenWithSave.Method = "POST";
//Save directly to stream
using(var stream = requestWrittenWithSave.GetRequestStream())
{
xDoc.Save(stream, SaveOptions.DisableFormatting);
}
long saveContentLength = requestWrittenWithSave.ContentLength; //316
//StreamWriter with ToString() method
using(var stream = requestWrittenWithString.GetRequestStream())
using(var writer = new StreamWriter(stream))
{
writer.Write(xDoc.ToString(SaveOptions.DisableFormatting));
}
long toStringContentLength = requestWrittenWithString.ContentLength; //313
答案 0 :(得分:1)
基于提供的不完整的代码示例(甚至不编译,从不介意产生完全描述的结果,因为第二个场景使用未声明的变量requestDoc
并且不向流发出XML声明),我有理由相信您实际上是在第一个场景中在流中获取UTF8 BOM。
我不知道XDocument
类中的设置会控制它。但是,显式指定用于输出的TextWriter
非常简单,StreamWriter
的默认编码不包括BOM(正如您在第二个场景中已经演示过的那样)。
这样的事情应该在第一个场景中修复你的问题:
using (var stream = requestWrittenWithSave.GetRequestStream())
using (TextWriter writer = new StreamWriter(stream))
{
xDoc.Save(writer, SaveOptions.DisableFormatting);
}
当然,您可以改为使用XDocument.ToString()
方法,如第二个示例所示。无论哪种方式都没问题。
如需将来参考,请重新阅读How to create a Minimal, Complete, and Verifiable example处的信息,以了解“MCVE”的含义。如果你提供一个好的MCVE,你可以为回答者节省大量的重复工作,并增加答案的可能性。