Angular/Web API 2 returns 包含 StreamContent 或 ByteArrayContent 的文件无效或损坏
Angular/Web API 2 returns invalid or corrupt file with StreamContent or ByteArrayContent
我正在尝试 return ASP.NET Web API 控制器中的文件。此文件是保存在 MemoryStream 中的动态生成的 PDF。
客户端(浏览器)接收文件成功,但打开文件时,发现所有页面都是空白。
问题是,如果我采用相同的 MemoryStream 并将其写入文件,则此磁盘文件显示正确,因此我认为问题与通过 Web 传输文件有关。
我的控制器是这样的:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
memStream.Position = 0;
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(memStream.ToArray()); //OR: new StreamContent(memStream);
return result;
}
试一下,如果我将流写入磁盘,它会正确显示:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
memStream.Position = 0;
using (var fs = new FileStream("C:\Temp\test.pdf", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
memStream.CopyTo(fs);
}
return null;
}
区别是:
- 保存在磁盘上的 PDF:34KB
- 通过网络传输的 PDF:60KB (!)
如果我比较两个文件的内容,主要区别是:
左边是网传的PDF;右边是保存到磁盘的 PDF。
我的代码有问题吗?
也许与编码有关?
谢谢!
我猜你应该像这样设置 ContentDisposition
和 ContentType
:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memStream.ToArray())
};
//this line
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "YourName.pdf"
};
//and this line
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
}
试试这个
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
//get buffer
var buffer = memStream.GetBuffer();
//content length for header
var contentLength = buffer.Length;
var statuscode = HttpStatusCode.OK;
var response = Request.CreateResponse(statuscode);
response.Content = new StreamContent(new MemoryStream(buffer));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = contentLength;
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse("inline; filename=my_filename.pdf", out contentDisposition)) {
response.Content.Headers.ContentDisposition = contentDisposition;
}
return response;
}
嗯,原来是客户端(浏览器)的问题,不是服务器的问题。我在前端使用 AngularJS,所以当收到响应时,Angular 自动将其转换为 Javascript 字符串。在那次转换中,文件的二进制内容以某种方式被改变了...
基本上是通过告诉 Angular 不要将响应转换为字符串来解决的:
$http.get(url, { responseType: 'arraybuffer' })
.then(function(response) {
var dataBlob = new Blob([response.data], { type: 'application/pdf'});
FileSaver.saveAs(dataBlob, 'myFile.pdf');
});
然后在 Angular File Saver 服务的帮助下将响应保存为文件。
我正在尝试 return ASP.NET Web API 控制器中的文件。此文件是保存在 MemoryStream 中的动态生成的 PDF。
客户端(浏览器)接收文件成功,但打开文件时,发现所有页面都是空白。
问题是,如果我采用相同的 MemoryStream 并将其写入文件,则此磁盘文件显示正确,因此我认为问题与通过 Web 传输文件有关。
我的控制器是这样的:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
memStream.Position = 0;
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(memStream.ToArray()); //OR: new StreamContent(memStream);
return result;
}
试一下,如果我将流写入磁盘,它会正确显示:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
memStream.Position = 0;
using (var fs = new FileStream("C:\Temp\test.pdf", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
memStream.CopyTo(fs);
}
return null;
}
区别是:
- 保存在磁盘上的 PDF:34KB
- 通过网络传输的 PDF:60KB (!)
如果我比较两个文件的内容,主要区别是:
左边是网传的PDF;右边是保存到磁盘的 PDF。
我的代码有问题吗? 也许与编码有关?
谢谢!
我猜你应该像这样设置 ContentDisposition
和 ContentType
:
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memStream.ToArray())
};
//this line
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = "YourName.pdf"
};
//and this line
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
}
试试这个
[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);
//get buffer
var buffer = memStream.GetBuffer();
//content length for header
var contentLength = buffer.Length;
var statuscode = HttpStatusCode.OK;
var response = Request.CreateResponse(statuscode);
response.Content = new StreamContent(new MemoryStream(buffer));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = contentLength;
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse("inline; filename=my_filename.pdf", out contentDisposition)) {
response.Content.Headers.ContentDisposition = contentDisposition;
}
return response;
}
嗯,原来是客户端(浏览器)的问题,不是服务器的问题。我在前端使用 AngularJS,所以当收到响应时,Angular 自动将其转换为 Javascript 字符串。在那次转换中,文件的二进制内容以某种方式被改变了...
基本上是通过告诉 Angular 不要将响应转换为字符串来解决的:
$http.get(url, { responseType: 'arraybuffer' })
.then(function(response) {
var dataBlob = new Blob([response.data], { type: 'application/pdf'});
FileSaver.saveAs(dataBlob, 'myFile.pdf');
});
然后在 Angular File Saver 服务的帮助下将响应保存为文件。