Von MSDN
MSDN has a document that lists a lot of the multipart subtypes. Die multipart/byteranges
vom Client zum Download für das Senden mehrerer Dateien in einer HTTP-Antwort am besten geeignet scheint Anwendung. Der fettgedruckte Teil ist besonders relevant.
Der Inhaltstyp multipart/byteranges ist als Teil des HTTP-Nachrichtenprotokolls definiert. Sie enthält zwei oder mehr Teile mit jeweils eigenen Feldern für Inhaltstyp und Inhaltsbereich. Die Teile werden mithilfe eines MIME-Randparameters getrennt. Es ermöglicht die binären sowie 7-Bit- und 8-Bit-Dateien werden als mehr Teile gesendet mit den Längen der Teile in der Kopfzeile eines jeden Teils angegeben wird. Beachten Sie, dass HTTP zwar die Verwendung von MIME für HTTP-Dokumente vorsieht, HTTP jedoch nicht streng MIME-konform ist. (Hervorhebung hinzugefügt.)
Von RFC2068
RFC2068, Abschnitt 19.2 eine Beschreibung von multipart/byteranges
zur Verfügung stellt. Auch hier ist der fett gedruckte Teil relevant. Jeder Bytebereich kann seinen eigenen Content-type
haben und es stellt sich heraus, dass er auch einen eigenen Content-disposition
haben kann.
Die multipart/byteranges Medientyp zwei oder mehr Teile, jedes mit seinem eigenen Content-Type und Content-Range Feldern. Die Teile werden mithilfe eines MIME-Randparameters getrennt. (Hervorhebung hinzugefügt.)
Die RFC auch diese technische Definition lautet:
Media Type name: multipart
Media subtype name: byteranges
Required parameters: boundary
Optional parameters: none
Encoding considerations: only "7bit", "8bit", or "binary" are permitted
Security considerations: none
Der beste Teil des RFC ist sein Beispiel, das die ASP.NET Bohrkern unten zeigt.
HTTP/1.1 206 Partial content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
--THIS_STRING_SEPARATES
Content-type: application/pdf
Content-range: bytes 500-999/8000
...the first range...
--THIS_STRING_SEPARATES
Content-type: application/pdf
Content-range: bytes 7000-7999/8000
...the second range
--THIS_STRING_SEPARATES--
Beachten Sie, dass sie zwei PDFs senden! Das ist genau das, was du brauchst.
Eine ASP.NET-Core-Ansatz
Hier ist ein Codebeispiel, das auf Firefox funktioniert. Das heißt, Firefox lädt drei Bilddateien herunter, die wir mit Paint öffnen können. The source is on GitHub.
Das Beispiel verwendet app.Run()
.Um das Beispiel an eine Controller-Aktion anzupassen, injizieren Sie IHttpContextAccessor
in Ihren Controller und schreiben Sie in Ihre Aktionsmethode auf _httpContextAccessor.HttpContext.Response
.
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
private const string CrLf = "\r\n";
private const string Boundary = "--THIS_STRING_SEPARATES";
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
var response = context.Response;
response.ContentType = $"multipart/byteranges; boundary={Boundary}";
// TODO Softcode the 'Content-length' header.
response.ContentLength = 13646;
var contentLength = response.ContentLength.Value;
await response.WriteAsync(Boundary + CrLf);
var blue = new FileInfo("./blue.jpg");
var red = new FileInfo("./red.jpg");
var green = new FileInfo("./green.jpg");
long start = 0;
long end = blue.Length;
await AddImage(response, blue, start, end, contentLength);
start = end + 1;
end = start + red.Length;
await AddImage(response, red, start, end, contentLength);
start = end + 1;
end = start + green.Length;
await AddImage(response, green, start, end, contentLength);
response.Body.Flush();
});
}
private async Task AddImage(HttpResponse response, FileInfo fileInfo,
long start, long end, long total)
{
var bytes = File.ReadAllBytes(fileInfo.FullName);
var file = new FileContentResult(bytes, "image/jpg");
await response
.WriteAsync($"Content-type: {file.ContentType.ToString()}" + CrLf);
await response
.WriteAsync($"Content-disposition: attachment; filename={fileInfo.Name}" + CrLf);
await response
.WriteAsync($"Content-range: bytes {start}-{end}/{total}" + CrLf);
await response.WriteAsync(CrLf);
await response.Body.WriteAsync(
file.FileContents,
offset: 0,
count: file.FileContents.Length);
await response.WriteAsync(CrLf);
await response.WriteAsync(Boundary + CrLf);
}
}
Hinweis: Dieser Beispielcode muss vor der Produktion refaktorisiert werden.
In Ihrer Ausgabe erwähnen Sie, dass dies "keine gute Methode zum Herunterladen von Dateien aus einem Browser aufgrund mangelnder Unterstützung ist, aber ich schreibe eine API und habe einen Client, den ich auch kontrolliere." Und in Shaun Luttins Antwort erwähnt er speziell Firefox. Zur Klärung, für welche Szenarien wird deine Antwort funktionieren? – chris
Dies funktioniert für APIs, bei denen Sie eine Reihe von Dateien zurückgeben möchten. In meinem Fall muss ich die Anzahl der HTTP-Anfragen aufgrund der hohen Latenz reduzieren. Dies funktioniert nicht für Websites, auf denen Sie mehrere Dateien herunterladen möchten, da Firefox der einzige Browser mit Unterstützung ist (ich habe es ausprobiert). Ich hoffe das hilft. –
Wie erreiche ich das Gegenteil: Ich habe einen Controller, der eine "multipart/mixed" in seiner Anfrage hat. Wie lese ich die einzelnen Teile/Streams? – Shimmy