C# 删除HTTP头后的空行
我正在寻找一些技巧/窍门,这些技巧/窍门将删除HTTP头后面的额外空行。任何帮助都将不胜感激。下面是一些细节 我正在通过HttpRequestMessageProperty对象向供应商的服务器发送一个由多个部分组成的MINE文档。MINE文档由两部分组成:SOAP信封和SOAP附件。矿山边界将多部分文档的两部分分隔开。请求被拒绝,因为HTTP头后面有额外的空行。我的代码工作基于上一个问题的建议。我已经将文档发送到供应商的服务器,并返回一个一般错误作为响应。我向供应商的IT人员询问了错误,他们告诉我“确保HTTP头中没有空行,HTTP头后只有一个空行。使用Fiddler,我发现HTTP头后(第一个--MIME_边界之前和 我复制并粘贴了下面请求的详细信息(请注意,我将信息缩写了一点,以使其保持如此简短……一点) 错误消息 消息格式不正确和/或无法解释 HTTP请求C# 删除HTTP头后的空行,c#,soap,http-headers,httprequest,C#,Soap,Http Headers,Httprequest,我正在寻找一些技巧/窍门,这些技巧/窍门将删除HTTP头后面的额外空行。任何帮助都将不胜感激。下面是一些细节 我正在通过HttpRequestMessageProperty对象向供应商的服务器发送一个由多个部分组成的MINE文档。MINE文档由两部分组成:SOAP信封和SOAP附件。矿山边界将多部分文档的两部分分隔开。请求被拒绝,因为HTTP头后面有额外的空行。我的代码工作基于上一个问题的建议。我已经将文档发送到供应商的服务器,并返回一个一般错误作为响应。我向供应商的IT人员询问了错误,他们告诉
POST https://xxxxxxx HTTP/1.1
Content-Type: multipart/related; type="application/xop+xml";start="<rootpart>";start-info="text/xml";boundary="MIME_boundary"
SOAPAction: "BulkRequestTransmitter"
Host: xxxxxxx
Content-Length: 12328
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
--MIME_boundary
Content-Type: application/xop+xml; type="text/xml"; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-Id: <rootpart>
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope>
<soap:Header>
...
</soap:Header>
<soap:Body>
<urn4:ACABulkRequestTransmitter version="1.0">
<urn1:BulkExchangeFile><inc:Include
href="cid:1095BCTransBaseAttachment.xml"
xmlns:inc="http://www.w3.org/2004/08/xop/include"/></urn1:BulkExchangeFile>
</urn4:ACABulkRequestTransmitter>
</soap:Body>
</soap:Envelope>
--MIME_Boundary
Content-Type: text/xml; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Id: <1094C_Request_[TCC]_20200518T215105716Z.xml>
Content-Disposition: attachment; name="1094C_Request_[TCC]_20200518T215105716Z.xml"
[FormDataXml]
--MIME_boundary--
GzipMessageEncoderFactory
public class GZipMessageEncoderFactory : MessageEncoderFactory
{
MessageEncoder encoder;
//The GZip encoder wraps an inner encoder
//We require a factory to be passed in that will create this inner encoder
public GZipMessageEncoderFactory(MessageEncoderFactory messageEncoderFactory)
{
if (messageEncoderFactory == null)
throw new ArgumentNullException("messageEncoderFactory", "A valid message encoder factory must be passed to the GZipEncoder");
encoder = new GZipMessageEncoder(messageEncoderFactory.Encoder, this);
}
//The service framework uses this property to obtain an encoder from this encoder factory
public override MessageEncoder Encoder
{
get { return encoder; }
}
public override MessageVersion MessageVersion
{
get { return encoder.MessageVersion; }
}
//This is the actual GZip encoder
public class GZipMessageEncoder : MessageEncoder
{
//------------------- MTOM related stuff. Begin. ---------------------
private string _ContentType;
private string _MediaType;
protected MimeContent _MyContent;
protected MimePart _SoapMimeContent;
protected MimePart _AttachmentMimeContent;
protected GZipMessageEncoderFactory _Factory;
protected MimeParser _MimeParser;
private void SetupMTOM(GZipMessageEncoderFactory factory)
{
//
_ContentType = "multipart/related";
_MediaType = _ContentType;
//
// Create owned objects
//
_Factory = factory;
_MimeParser = new MimeParser();
//
// Create object for the mime content message
//
_SoapMimeContent = new MimePart()
{
ContentTypeStart = "application/xop+xml",
ContentType = "text/xml",
ContentId = MyRequestService.EnvelopeContentID,
CharSet = "UTF-8",
TransferEncoding = "8bit"
};
_AttachmentMimeContent = new MimePart()
{
ContentType = "application/xml",
ContentId = MyRequestService.AttachmentContentID,
TransferEncoding = "7bit"
};
_MyContent = new MimeContent()
{
Boundary = MyRequestService.MIMEBoundary
};
_MyContent.Parts.Add(_SoapMimeContent);
_MyContent.Parts.Add(_AttachmentMimeContent);
_MyContent.SetAsStartPart(_SoapMimeContent);
}
//------------------- MTOM related stuff. End. ----------------------
static string GZipContentType = "application/x-gzip";
//This implementation wraps an inner encoder that actually converts a WCF Message
//into textual XML, binary XML or some other format. This implementation then compresses the results.
//The opposite happens when reading messages.
//This member stores this inner encoder.
MessageEncoder innerEncoder;
//We require an inner encoder to be supplied (see comment above)
internal GZipMessageEncoder(MessageEncoder messageEncoder, GZipMessageEncoderFactory factory)
: base()
{
if (messageEncoder == null)
throw new ArgumentNullException("messageEncoder", "A valid message encoder must be passed to the GZipEncoder");
innerEncoder = messageEncoder;
SetupMTOM(factory);
}
public override string ContentType
{
get { return GZipContentType; }
}
public override string MediaType
{
get { return GZipContentType; }
}
//SOAP version to use - we delegate to the inner encoder for this
public override MessageVersion MessageVersion
{
get { return innerEncoder.MessageVersion; }
}
//Helper method to compress an array of bytes
static ArraySegment<byte> CompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager, int messageOffset)
{
MemoryStream memoryStream = new MemoryStream();
using (GZipStream gzStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
{
gzStream.Write(buffer.Array, buffer.Offset, buffer.Count);
}
byte[] compressedBytes = memoryStream.ToArray();
int totalLength = messageOffset + compressedBytes.Length;
byte[] bufferedBytes = bufferManager.TakeBuffer(totalLength);
Array.Copy(compressedBytes, 0, bufferedBytes, messageOffset, compressedBytes.Length);
bufferManager.ReturnBuffer(buffer.Array);
ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferedBytes, messageOffset, bufferedBytes.Length - messageOffset);
return byteArray;
}
//Helper method to decompress an array of bytes
static ArraySegment<byte> DecompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager)
{
MemoryStream memoryStream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count);
MemoryStream decompressedStream = new MemoryStream();
int totalRead = 0;
int blockSize = 1024;
byte[] tempBuffer = bufferManager.TakeBuffer(blockSize);
using (GZipStream gzStream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
while (true)
{
int bytesRead = gzStream.Read(tempBuffer, 0, blockSize);
if (bytesRead == 0)
break;
decompressedStream.Write(tempBuffer, 0, bytesRead);
totalRead += bytesRead;
}
}
bufferManager.ReturnBuffer(tempBuffer);
byte[] decompressedBytes = decompressedStream.ToArray();
byte[] bufferManagerBuffer = bufferManager.TakeBuffer(decompressedBytes.Length + buffer.Offset);
Array.Copy(buffer.Array, 0, bufferManagerBuffer, 0, buffer.Offset);
Array.Copy(decompressedBytes, 0, bufferManagerBuffer, buffer.Offset, decompressedBytes.Length);
ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferManagerBuffer, buffer.Offset, decompressedBytes.Length);
bufferManager.ReturnBuffer(buffer.Array);
return byteArray;
}
//One of the two main entry points into the encoder. Called by WCF to decode a buffered byte array into a Message.
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
//ArraySegment<byte> decompressedBuffer = DecompressBuffer(buffer, bufferManager);
SwaEncoder mtomEncoder = new SwaEncoder(innerEncoder, _Factory, "text/xml");
Message returnMessage = mtomEncoder.ReadMessage(buffer, bufferManager, contentType);
returnMessage.Properties.Encoder = mtomEncoder;
return returnMessage;
}
//One of the two main entry points into the encoder. Called by WCF to encode a Message into a buffered byte array.
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
ArraySegment<byte> buffer = innerEncoder.WriteMessage(message, maxMessageSize, bufferManager, 0);
var requestSOAPEnvelopeXml = System.Text.Encoding.UTF8.GetString(buffer.Array);
//forget whatever we got from WCF, replace the whole stupid thing with a hand-made envelope
requestSOAPEnvelopeXml = MyRequestService.ReadSoapEnvelopeFile() + System.Environment.NewLine;
//Here you are getting 1094\1095 forms xml payload.
string fileContent = MyRequestService.GetAttachmentFileContent();
//Here comes the MTOMing...
_SoapMimeContent.Content = System.Text.Encoding.UTF8.GetBytes(requestSOAPEnvelopeXml);
_AttachmentMimeContent.Content = System.Text.Encoding.UTF8.GetBytes(fileContent);
_MyContent.Parts.Where(m => m.ContentId != null && m.ContentId.Equals(MyRequestService.AttachmentContentID)).Single().ContentDisposition = MyRequestService.GetFileName();
// Now create the message content for the stream
byte[] MimeContentBytes = _MimeParser.SerializeMimeContent(_MyContent);
int MimeContentLength = MimeContentBytes.Length;
// Write the mime content into the section of the buffer passed into the method
byte[] TargetBuffer = bufferManager.TakeBuffer(MimeContentLength + messageOffset);
Array.Copy(MimeContentBytes, 0, TargetBuffer, messageOffset, MimeContentLength);
// Return the segment of the buffer to the framework
return CompressBuffer(new ArraySegment<byte>(TargetBuffer, messageOffset, MimeContentLength), bufferManager, messageOffset);
}
public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType)
{
//Pass false for the "leaveOpen" parameter to the GZipStream constructor.
//This will ensure that the inner stream gets closed when the message gets closed, which
//will ensure that resources are available for reuse/release.
GZipStream gzStream = new GZipStream(stream, CompressionMode.Decompress, false);
return innerEncoder.ReadMessage(gzStream, maxSizeOfHeaders);
}
public override void WriteMessage(Message message, System.IO.Stream stream)
{
using (GZipStream gzStream = new GZipStream(stream, CompressionMode.Compress, true))
{
innerEncoder.WriteMessage(message, gzStream);
}
// innerEncoder.WriteMessage(message, gzStream) depends on that it can flush data by flushing
// the stream passed in, but the implementation of GZipStream.Flush will not flush underlying
// stream, so we need to flush here.
stream.Flush();
}
public override bool IsContentTypeSupported(string contentType)
{
return true;
}
}
}
公共类GZipMessageEncoderFactory:MessageEncoderFactory
{
信息编码器;
//GZip编码器封装了一个内部编码器
//我们需要传入一个工厂来创建这个内部编码器
公共GZipMessageEncoderFactory(MessageEncoderFactory MessageEncoderFactory)
{
if(messageEncoderFactory==null)
抛出新的ArgumentNullException(“messageEncoderFactory”,“必须将有效的消息编码器工厂传递给GZipEncoder”);
编码器=新的GZipMessageEncoder(messageEncoderFactory.encoder,this);
}
//服务框架使用此属性从此编码器工厂获取编码器
公共覆盖消息编码器
{
获取{返回编码器;}
}
公共覆盖消息版本消息版本
{
获取{return encoder.MessageVersion;}
}
//这是实际的GZip编码器
公共类GZipMessageEncoder:MessageEncoder
{
//-------------------MTOM相关的东西,开始---------------------
私有字符串_ContentType;
私有字符串_MediaType;
受保护的微生物含量;
受保护的MimePart\u SOAPMIMEMENT;
受保护的MimePart\u附件MIMEContent;
受保护的GZipMessageEncoderFactory\u工厂;
受保护的MimeParser\u MimeParser;
专用void SetupMTOM(GZipMessageEncoderFactory工厂)
{
//
_ContentType=“多部分/相关”;
_MediaType=\u ContentType;
//
//创建拥有的对象
//
_工厂=工厂;
_MimeParser=新的MimeParser();
//
//为mime内容消息创建对象
//
_SoapMimeContent=新的MimePart()
{
ContentTypeStart=“应用程序/xop+xml”,
ContentType=“text/xml”,
ContentId=MyRequestService.EnvelopeContentID,
CharSet=“UTF-8”,
Transferncode=“8bit”
};
_AttachmentMimeContent=新的MimePart()
{
ContentType=“应用程序/xml”,
ContentId=MyRequestService.AttachmentContentID,
transferncode=“7bit”
};
_MyContent=新的mimcontent()
{
Boundary=MyRequestService.mimebundary
};
_MyContent.Parts.Add(_SoapMimeContent);
_MyContent.Parts.Add(_AttachmentMimeContent);
_菌落总数(SoapMimeContent);
}
//-------------------与MTOM相关的东西。结束----------------------
静态字符串GZipContentType=“应用程序/x-gzip”;
//此实现封装了一个内部编码器,该编码器实际转换WCF消息
//转换为文本XML、二进制XML或其他格式。此实现然后压缩结果。
//阅读信息时,情况正好相反。
//此成员存储此内部编码器。
消息编码器;
//我们需要提供一个内部编码器(见上面的评论)
内部GZipMessageEncoder(MessageEncoder MessageEncoder,GZipMessageEncoder工厂)
:base()
{
if(messageEncoder==null)
抛出新的ArgumentNullException(“messageEncoder”,“必须将有效的消息编码器传递给GZipEncoder”);
innerEncoder=messageEncoder;
SetupMTOM(工厂);
}
公共重写字符串ContentType
{
获取{return gzip内容类型;}
}
公共重写字符串MediaType
{
获取{return gzip内容类型;}
}
//要使用的SOAP版本-为此,我们将委托给内部编码器
公共覆盖消息版本消息版本
{
获取{return innerEncoder.MessageVersion;}
}
//用于压缩字节数组的Helper方法
静态ArraySegment CompressBuffer(ArraySegment buffer、BufferManager BufferManager、int messageOffset)
{
MemoryStream MemoryStream=n
public class GZipMessageEncoderFactory : MessageEncoderFactory
{
MessageEncoder encoder;
//The GZip encoder wraps an inner encoder
//We require a factory to be passed in that will create this inner encoder
public GZipMessageEncoderFactory(MessageEncoderFactory messageEncoderFactory)
{
if (messageEncoderFactory == null)
throw new ArgumentNullException("messageEncoderFactory", "A valid message encoder factory must be passed to the GZipEncoder");
encoder = new GZipMessageEncoder(messageEncoderFactory.Encoder, this);
}
//The service framework uses this property to obtain an encoder from this encoder factory
public override MessageEncoder Encoder
{
get { return encoder; }
}
public override MessageVersion MessageVersion
{
get { return encoder.MessageVersion; }
}
//This is the actual GZip encoder
public class GZipMessageEncoder : MessageEncoder
{
//------------------- MTOM related stuff. Begin. ---------------------
private string _ContentType;
private string _MediaType;
protected MimeContent _MyContent;
protected MimePart _SoapMimeContent;
protected MimePart _AttachmentMimeContent;
protected GZipMessageEncoderFactory _Factory;
protected MimeParser _MimeParser;
private void SetupMTOM(GZipMessageEncoderFactory factory)
{
//
_ContentType = "multipart/related";
_MediaType = _ContentType;
//
// Create owned objects
//
_Factory = factory;
_MimeParser = new MimeParser();
//
// Create object for the mime content message
//
_SoapMimeContent = new MimePart()
{
ContentTypeStart = "application/xop+xml",
ContentType = "text/xml",
ContentId = MyRequestService.EnvelopeContentID,
CharSet = "UTF-8",
TransferEncoding = "8bit"
};
_AttachmentMimeContent = new MimePart()
{
ContentType = "application/xml",
ContentId = MyRequestService.AttachmentContentID,
TransferEncoding = "7bit"
};
_MyContent = new MimeContent()
{
Boundary = MyRequestService.MIMEBoundary
};
_MyContent.Parts.Add(_SoapMimeContent);
_MyContent.Parts.Add(_AttachmentMimeContent);
_MyContent.SetAsStartPart(_SoapMimeContent);
}
//------------------- MTOM related stuff. End. ----------------------
static string GZipContentType = "application/x-gzip";
//This implementation wraps an inner encoder that actually converts a WCF Message
//into textual XML, binary XML or some other format. This implementation then compresses the results.
//The opposite happens when reading messages.
//This member stores this inner encoder.
MessageEncoder innerEncoder;
//We require an inner encoder to be supplied (see comment above)
internal GZipMessageEncoder(MessageEncoder messageEncoder, GZipMessageEncoderFactory factory)
: base()
{
if (messageEncoder == null)
throw new ArgumentNullException("messageEncoder", "A valid message encoder must be passed to the GZipEncoder");
innerEncoder = messageEncoder;
SetupMTOM(factory);
}
public override string ContentType
{
get { return GZipContentType; }
}
public override string MediaType
{
get { return GZipContentType; }
}
//SOAP version to use - we delegate to the inner encoder for this
public override MessageVersion MessageVersion
{
get { return innerEncoder.MessageVersion; }
}
//Helper method to compress an array of bytes
static ArraySegment<byte> CompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager, int messageOffset)
{
MemoryStream memoryStream = new MemoryStream();
using (GZipStream gzStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
{
gzStream.Write(buffer.Array, buffer.Offset, buffer.Count);
}
byte[] compressedBytes = memoryStream.ToArray();
int totalLength = messageOffset + compressedBytes.Length;
byte[] bufferedBytes = bufferManager.TakeBuffer(totalLength);
Array.Copy(compressedBytes, 0, bufferedBytes, messageOffset, compressedBytes.Length);
bufferManager.ReturnBuffer(buffer.Array);
ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferedBytes, messageOffset, bufferedBytes.Length - messageOffset);
return byteArray;
}
//Helper method to decompress an array of bytes
static ArraySegment<byte> DecompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager)
{
MemoryStream memoryStream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count);
MemoryStream decompressedStream = new MemoryStream();
int totalRead = 0;
int blockSize = 1024;
byte[] tempBuffer = bufferManager.TakeBuffer(blockSize);
using (GZipStream gzStream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
while (true)
{
int bytesRead = gzStream.Read(tempBuffer, 0, blockSize);
if (bytesRead == 0)
break;
decompressedStream.Write(tempBuffer, 0, bytesRead);
totalRead += bytesRead;
}
}
bufferManager.ReturnBuffer(tempBuffer);
byte[] decompressedBytes = decompressedStream.ToArray();
byte[] bufferManagerBuffer = bufferManager.TakeBuffer(decompressedBytes.Length + buffer.Offset);
Array.Copy(buffer.Array, 0, bufferManagerBuffer, 0, buffer.Offset);
Array.Copy(decompressedBytes, 0, bufferManagerBuffer, buffer.Offset, decompressedBytes.Length);
ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferManagerBuffer, buffer.Offset, decompressedBytes.Length);
bufferManager.ReturnBuffer(buffer.Array);
return byteArray;
}
//One of the two main entry points into the encoder. Called by WCF to decode a buffered byte array into a Message.
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
//ArraySegment<byte> decompressedBuffer = DecompressBuffer(buffer, bufferManager);
SwaEncoder mtomEncoder = new SwaEncoder(innerEncoder, _Factory, "text/xml");
Message returnMessage = mtomEncoder.ReadMessage(buffer, bufferManager, contentType);
returnMessage.Properties.Encoder = mtomEncoder;
return returnMessage;
}
//One of the two main entry points into the encoder. Called by WCF to encode a Message into a buffered byte array.
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
ArraySegment<byte> buffer = innerEncoder.WriteMessage(message, maxMessageSize, bufferManager, 0);
var requestSOAPEnvelopeXml = System.Text.Encoding.UTF8.GetString(buffer.Array);
//forget whatever we got from WCF, replace the whole stupid thing with a hand-made envelope
requestSOAPEnvelopeXml = MyRequestService.ReadSoapEnvelopeFile() + System.Environment.NewLine;
//Here you are getting 1094\1095 forms xml payload.
string fileContent = MyRequestService.GetAttachmentFileContent();
//Here comes the MTOMing...
_SoapMimeContent.Content = System.Text.Encoding.UTF8.GetBytes(requestSOAPEnvelopeXml);
_AttachmentMimeContent.Content = System.Text.Encoding.UTF8.GetBytes(fileContent);
_MyContent.Parts.Where(m => m.ContentId != null && m.ContentId.Equals(MyRequestService.AttachmentContentID)).Single().ContentDisposition = MyRequestService.GetFileName();
// Now create the message content for the stream
byte[] MimeContentBytes = _MimeParser.SerializeMimeContent(_MyContent);
int MimeContentLength = MimeContentBytes.Length;
// Write the mime content into the section of the buffer passed into the method
byte[] TargetBuffer = bufferManager.TakeBuffer(MimeContentLength + messageOffset);
Array.Copy(MimeContentBytes, 0, TargetBuffer, messageOffset, MimeContentLength);
// Return the segment of the buffer to the framework
return CompressBuffer(new ArraySegment<byte>(TargetBuffer, messageOffset, MimeContentLength), bufferManager, messageOffset);
}
public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType)
{
//Pass false for the "leaveOpen" parameter to the GZipStream constructor.
//This will ensure that the inner stream gets closed when the message gets closed, which
//will ensure that resources are available for reuse/release.
GZipStream gzStream = new GZipStream(stream, CompressionMode.Decompress, false);
return innerEncoder.ReadMessage(gzStream, maxSizeOfHeaders);
}
public override void WriteMessage(Message message, System.IO.Stream stream)
{
using (GZipStream gzStream = new GZipStream(stream, CompressionMode.Compress, true))
{
innerEncoder.WriteMessage(message, gzStream);
}
// innerEncoder.WriteMessage(message, gzStream) depends on that it can flush data by flushing
// the stream passed in, but the implementation of GZipStream.Flush will not flush underlying
// stream, so we need to flush here.
stream.Flush();
}
public override bool IsContentTypeSupported(string contentType)
{
return true;
}
}
}