次のコードを使用して、asp.net WebAPIからクライアントにZipファイルを返そうとしています。
private byte[] CreateZip(string data)
{
using (var ms = new MemoryStream())
{
using (var ar = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
var file = archive.CreateEntry("file.html");
using (var entryStream = file.Open())
using (var sw = new StreamWriter(entryStream))
{
sw .Write(value);
}
}
return memoryStream.ToArray();
}
}
public HttpResponseMessage Post([FromBody] string data)
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(CreateZip(data));
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/Zip, application/octet-stream");
return result;
}
このコードを実行すると、次のエラーが発生します。
ExceptionMessage ":"値 'application/Zip、application/octet-stream'の形式が無効です。 "
これはJSコードです:
$.ajax({
type: "POST",
url: url,
data: data,
dataType: application/x-www-form-urlencoded
});
なぜこれが起こるのか説明はありますか?私は本当にあなたの助けの人に感謝します
$.ajax
はテキスト応答を処理し、コンテンツを(utf-8)デコードしようとします。Zipファイルはテキストではないため、破損したコンテンツが表示されます。 jQueryはバイナリコンテンツをサポートしていないため、 this リンクを使用してjQueryにajaxトランスポートを追加するか、XmlHttpRequestを直接使用する必要があります。 xhrを使用する場合は、xhr.responseType = "blob"
を設定し、xhr.response
からblobを読み取る必要があります。
// with xhr.responseType = "arraybuffer"
var arraybuffer = xhr.response;
var blob = new Blob([arraybuffer], {type:"application/Zip"});
saveAs(blob, "example.Zip");
// with xhr.responseType = "blob"
var blob = xhr.response;
saveAs(blob, "example.Zip");
Edit: examples:
with jquery.binarytransport.js (BlobまたはArrayBufferをダウンロードできるライブラリならどれでもかまいません)
$.ajax({
url: url,
type: "POST",
contentType: "application/json",
dataType: "binary", // to use the binary transport
// responseType:'blob', this is the default
data: data,
processData: false,
success: function (blob) {
// the result is a blob, we can trigger the download directly
saveAs(blob, "example.Zip");
}
// [...]
});
生のXMLHttpRequestを使用すると、 this の質問が表示されます。ブロブを取得するには、xhr.responseType = "blob"
を追加する必要があります。
個人的には、jQueryでajaxトランスポートを使用することをお勧めします。これは非常に簡単です。ライブラリをダウンロードしてプロジェクトに含め、次のように記述する必要があります。dataType: "binary".
これは、DotNetZip(Ionic.Zip
)を使用したAPIコードです。
[HttpPost]
public HttpResponseMessage ZipDocs([FromBody] string[] docs)
{
using (ZipFile Zip = new ZipFile())
{
//this code takes an array of documents' paths and Zip them
Zip.AddFiles(docs, false, "");
return ZipContentResult(Zip);
}
}
protected HttpResponseMessage ZipContentResult(ZipFile zipFile)
{
var pushStreamContent = new PushStreamContent((stream, content, context) =>
{
zipFile.Save(stream);
stream.Close();
}, "application/Zip");
return new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };
}
これが私のために働いた私の解決策です
C#側
public IActionResult GetZip([FromBody] List<DocumentAndSourceDto> documents)
{
List<Document> listOfDocuments = new List<Document>();
foreach (DocumentAndSourceDto doc in documents)
listOfDocuments.Add(_documentService.GetDocumentWithServerPath(doc.Id));
using (var ms = new MemoryStream())
{
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var attachment in listOfDocuments)
{
var entry = zipArchive.CreateEntry(attachment.FileName);
using (var fileStream = new FileStream(attachment.FilePath, FileMode.Open))
using (var entryStream = entry.Open())
{
fileStream.CopyTo(entryStream);
}
}
}
ms.Position = 0;
return File(ms.ToArray(), "application/Zip");
}
throw new ErrorException("Can't Zip files");
}
ここでms.Position = 0;
をお見逃しなく
前面(角度4):
downloadZip(datas: any) {
const headers = new Headers({
'Content-Type': 'application/json',
'Accept': 'application/Zip'
});
const options = new RequestOptions({ headers: headers, withCredentials: true, responseType: ResponseContentType.ArrayBuffer });
const body = JSON.stringify(datas);
return this.authHttp.post(`${environment.apiBaseUrl}api/documents/Zip`, body, options)
.map((response: Response) => {
const blob = new Blob([response.blob()], { type: 'application/Zip' });
FileSaver.saveAs(blob, 'logs.Zip');
})
.catch(this.handleError);
}
これで、複数のファイルをZipにダウンロードできるようになりました。
MediaTypeHeaderValue
のコンストラクターに渡す値の形式が無効です。また、ヘッダー値に複数のコンテンツタイプを追加しようとしています。
コンテンツタイプヘッダーは単一のタイプ/サブタイプを取り、その後にセミコロンで区切られたオプションのパラメーター;
例えば:
Content-Type: text/html; charset=ISO-8859-4
結果を得るには、どちらを使用するかを決定する必要があります。 application/Zip
またはapplication/octet-stream
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/Zip");
また、例外を回避するために、MediaTypeHeaderValue.TryParse
メソッドを使用できます
var contentTypeString = "application/Zip";
MediaTypeHeaderValue contentType = null;
if(MediaTypeHeaderValue.TryParse(contentTypeString, out contentType)) {
result.Content.Headers.ContentType = contentType;
}
[HttpGet("api/DownloadZip")]
public async Task<IActionResult> Download()
{
var path = "C:\\test.Zip";
var memory = new MemoryStream();
using (var stream = new FileStream(path, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, GetContentType(path), Path.GetFileName(path));
}
class Program
{
static string url = "http://localhost:5000/api/DownloadZip";
static async Task Main(string[] args)
{
var p = @"c:\temp1\test.Zip";
WebClient webClient = new WebClient();
webClient.DownloadFile(new Uri(url), p);
Console.WriteLine("ENTER to exit...");
Console.ReadLine();
}
}