streamReader.ReadToEndAsync() 改变消息内容
Posted
技术标签:
【中文标题】streamReader.ReadToEndAsync() 改变消息内容【英文标题】:streamReader.ReadToEndAsync() changing message content 【发布时间】:2020-11-24 05:40:20 【问题描述】:我有一个 .Net Core 3.1 Web API 需要与外部服务交互,该服务提供来自 WCF 服务的多部分/相关响应,上下文中的附件如下所示。
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 1790633
Content-Type: multipart/related; type="text/xml"; start="<8fb5b3efa6474add9032cb80870dc065>"; boundary="------=_Part_20200731120159.494997"
Server: Microsoft-IIS/10.0
Set-Cookie: ASP.NET_SessionId=jga2opbhoirgnhjhmmsuxi1k; path=/; HttpOnly; SameSite=Lax
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Set-Cookie: ARRAffinity=f7b4f7f5d8cbd8c8bc5d9a4bf49e8b5938412c4294f6e2c2b5c2d5cfc4b4d437;Path=/;HttpOnly;Domain=lparouterpoc.azurewebsites.net
Date: Fri, 31 Jul 2020 13:33:04 GMT
--------=_Part_20200731120159.494997
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <8fb5b3efa6474add9032cb80870dc065>
<?xml version="1.0" encoding="iso-8859-1"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
</SOAP-ENV:Envelope>
--------=_Part_20200731120159.494997
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-Id: 7b1fff220df5@xxxxx
%PDF-1.5
%����
...
Additional characters added in here
...
%%EOF
--------=_Part_20200731120159.494997
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-Id: 844eb478dc05@xxxxx
%PDF-1.5
...
Additional characters added here
...
%%EOF
--------=_Part_20200731120159.494997--
使用 SOAP UI,我看到有附件,但每个附件都是空白 PDF。
.Net Core API 中的代码是
using (var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
var stream = await response.Content.ReadAsStreamAsync();
using var streamReader = new StreamReader(stream, Encoding.UTF8);
var message = await streamReader.ReadToEndAsync(); // This is where output is changed to add additional characters
var headers = response.Headers;
return new customResponse
ContentResult = new ContentResult
Content = message,
ContentType = response.Content.Headers.ContentType?.ToString(),
StatusCode = (int)response.StatusCode
,
ResponseHeaders = headers
;
下图显示了一个示例,说明附加字符的出现导致 PDF 无效\损坏\空白。
另一个特点是内容长度从 1021690 到 1790633。
到目前为止,我已经能够对其进行调试并在文件进入消息(字符串)之前测试它们是否正确,因为我能够在检查文件时读取多部分内容并将文件写入磁盘确实正确使用
var content = await response.Content.ReadAsMultipartAsync();
for (var i = 0; i < content.Contents.Count; i++)
var item = content.Contents[i];
if (item.Headers.ContentType.ToString() == "application/octet-stream")
var bytes = await item.ReadAsByteArrayAsync();
File.WriteAllBytes(@$"c:\temp\i.pdf", bytes);
然后遍历content.Contents
。
如果有人能告诉我为什么会发生这种情况以及如何阻止这种情况发生,我将不胜感激
进一步调查和假设是否可以归结为编码?附件的 WCF 服务是 TransferEncoding = "binary"
图像的左侧和中间是相同的,中间从我的 API 直接写入磁盘(不是我需要的)显示文件可以读写。
右侧是服务的直接输出,返回到 SOAP UI 并按预期下载。
在监视窗口中查看响应时,传输编码为空,因此对如何解决此问题感到有些困惑。
【问题讨论】:
这是意料之中的。您正在以 utf-8 编码字符串的形式读取整个响应,但事实并非如此 (Content-Transfer-Encoding: binary
)。
查看正在被替换的现有服务,内容传输编码可能需要更改为 8 位
如果您再次将其读取为 utf-8,仍然会导致数据损坏。
使用 8 位,因为我需要匹配要替换的服务,我尝试了其他编码选项,每个结果都在 Unexpected end of MIME multipart stream. MIME multipart message is not complete.
Unexpected end of MIME multipart stream. MIME multipart message is not complete.
还有什么可以\将\应该工作?
没什么。您不能以任何编码将此响应作为字符串读取。这是一个字节数组。
【参考方案1】:
试试这个,
public async Task<HttpResponseMessage> Post(string requestBody, string action)
using (var request = new HttpRequestMessage(HttpMethod.Post, ""))
request.Headers.Add("SOAPAction", action);
request.Content = new StringContent(requestBody, Encoding.UTF8, "text/xml");
var response = await Client.SendAsync(request);
return response;
然后在你的控制器中像这样返回它
var result = await _service.Post(requestBody, action);
var stream = await result.Content.ReadAsStreamAsync();
await stream.CopyToAsync(HttpContext.Response.Body);
【讨论】:
以上是关于streamReader.ReadToEndAsync() 改变消息内容的主要内容,如果未能解决你的问题,请参考以下文章