So erhalten Sie den Dateinamen von der Inhaltsdisposition

Lesezeit: 8 Minuten

Benutzer-Avatar
Arun Siwan

Ich habe eine Datei als Antwort von Ajax heruntergeladen. So erhalten Sie den Dateinamen und den Dateityp von content-disposition und zeigen Sie ein Miniaturbild dafür an. Ich habe viele Suchergebnisse erhalten, konnte aber nicht den richtigen Weg finden.

$(".download_btn").click(function () {
  var uiid = $(this).data("id2");

  $.ajax({
    url: "http://localhost:8080/prj/" + data + "/" + uiid + "/getfile",
    type: "GET",
    error: function (jqXHR, textStatus, errorThrown) {
      console.log(textStatus, errorThrown);
    },
    success: function (response, status, xhr) {
      var header = xhr.getResponseHeader('Content-Disposition');
      console.log(header);     
    }
});

Konsolenausgabe:

inline; filename=demo3.png

  • Was sagt die Konsole?

    – Matthew

    2. Dezember 2016 um 19:13 Uhr

  • Warum stellst du dich ein window.location.href ="http://localhost:8080/prj/" + data + "/" + uiid + "/getfile";? Dadurch verlässt der Browser die Seite und zeigt nur diese URL an. Wie soll eine Miniaturansicht für das Bild angezeigt werden, wenn Sie die Seite verlassen haben? Warum benötigen Sie den Dateinamen, den der Server zum Speichern der Datei vorschlägt, um ein Miniaturbild zu erstellen?

    – QUentin

    2. Dezember 2016 um 19:16 Uhr

  • Das Erhalten des Dateinamens aus der Inhaltsdisposition ist ein Problem. Sie können den Dateityp daraus nicht entnehmen, zumindest nicht zuverlässig, dafür ist der Content-Type-Header da. Die Thumbnail-Anzeige würde aus den Daten kommen und ist ein völlig separates Problem.

    – QUentin

    2. Dezember 2016 um 19:18 Uhr

  • Ich brauche einen Dateinamen, der neben dem Miniaturbild angezeigt wird.

    – Arun Sivan

    2. Dezember 2016 um 19:18 Uhr

  • aber ich konnte den Dateityp aus dem Dateinamen selbst finden filename.jpg

    – Arun Sivan

    2. Dezember 2016 um 19:20 Uhr

Benutzer-Avatar
Wintersoldat

Hier ist, wie ich es irgendwann verwendet habe. Ich gehe davon aus, dass Sie den Anhang als Serverantwort bereitstellen.

Ich setze den Response-Header so von meinem REST-Service response.setHeader("Content-Disposition", "attachment;filename=XYZ.csv");

function(response, status, xhr){
    var filename = "";
    var disposition = xhr.getResponseHeader('Content-Disposition');
    if (disposition && disposition.indexOf('attachment') !== -1) {
        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        var matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) { 
          filename = matches[1].replace(/['"]/g, '');
        }
    }
}

BEARBEITEN: Bearbeiten Sie die Antwort entsprechend Ihrer Frage – Verwendung des Wortes inline Anstatt von attachment

function(response, status, xhr){
    var filename = "";
    var disposition = xhr.getResponseHeader('Content-Disposition');
    if (disposition && disposition.indexOf('inline') !== -1) {
        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        var matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) { 
          filename = matches[1].replace(/['"]/g, '');
        }
    }
}

Mehr hier

  • was macht filename = matches[1].replace(/['"]/g, ''); tun?

    – Edmundpie

    7. September 2018 um 3:17 Uhr

  • Diese Lösung funktioniert nicht in Fällen wie diesen: Anhang; Dateiname*=UTF-8”Dateiname.txt. Mit dieser Regex lautet der Dateiname UTF-8Dateiname.txt.

    – Felipe Desiderati

    10. Juli 2019 um 22:01 Uhr


  • Ich kann nicht glauben, wie knarlig und hässlich JavaScript manchmal ist …

    – Störsender

    4. März 2020 um 10:07 Uhr


  • Um das utf8-Muster auch so abzugleichen: dis = "attachment; filename*=UTF-8''filename.pdf" Versuchen /filename\*?=([^']*'')?([^;]*)/.exec(dis)[2]

    – Ruuter

    7. Oktober 2020 um 16:30 Uhr


  • Ich denke, es wäre besser zu verwenden disposition.startsWith("attachment") Anstatt von disposition.indexOf('attachment') !== -1da der Dateiname eine enthalten kann Anhang

    – foske

    21. Mai 2021 um 12:41 Uhr

Benutzer-Avatar
Shivam Puri

Dies ist eine Verbesserung der Antwort von marjon4.

Ein stark vereinfachter Weg zur ausgewählten Antwort wäre die Verwendung von split wie folgt;

var fileName = xhr.getResponseHeader('content-disposition').split('filename=")[1].split(";')[0];

Hinweis: Diese Lösung funktioniert möglicherweise nicht wie erwartet, wenn Ihr Dateiname selbst ein Semikolon (;)

  • Würde dies nicht fehlschlagen, wenn der Dateiname ein Semikolon darin wäre?

    – Mathew Alden

    30. Dezember 2020 um 23:14 Uhr

  • Dies ist ein naiver Ansatz, nicht zu empfehlen. Dies könnte zu falschen Ergebnissen führen, wenn der Dateiname Semikolons enthält. Fehlende Unterstützung für filename*=UTF-8''.

    – Steven Likens

    18. Februar 2021 um 14:44 Uhr

  • Die Lösung funktioniert gut mit filename*=UTF-8' ' format Das gesamte Format, auf das Sie sich wahrscheinlich beziehen, geht so content-disposition: "attachment; filename=document.pdf; filename*=UTF-8''document.pdf". Bitte versuchen Sie zu verstehen und zu antworten, bevor Sie sagen, dass es nicht funktionieren wird! Und ja, aus technischer Sicht funktioniert diese Lösung nicht, wenn der Dateiname selbst Semikolons enthält. Aber in den meisten Fällen enthält der Dateiname keine Semikolons, also hat es mit diesem Vorwand für mich gut funktioniert! (Ich füge meiner Antwort noch einen Hinweis dazu hinzu.)

    – Shivam Puri

    3. März 2021 um 6:11 Uhr


  • Es funktioniert auch nicht für den Grenzfall, wenn der Dateiname selbst enthält filename=.

    – Aleksej

    19. Mai 2021 um 15:03 Uhr

  • Ich würde .replaceAll(”’,”) hinzufügen, sonst scheint es bei Namen mit Leerzeichen fehlzuschlagen

    – Inigo EC

    30. Januar um 19:24 Uhr

Benutzer-Avatar
Marjon4

Oder einfach nur:

var fileName = xhr.getResponseHeader('Content-Disposition').split("filename=")[1];

  • Mit folgendem Format funktioniert es nicht: content-disposition: "attachment; filename=document.pdf; filename*=UTF-8''document.pdf"

    – AlexM

    30. April 2020 um 3:42 Uhr

  • Antwort hinzugefügt, um das von @AlexM erwähnte Problem zu beheben

    – Shivam Puri

    3. Juni 2020 um 12:43 Uhr


Bei mir sieht der Header so aus:

attachment; filename="test-file3.txt"

Daher konnte ich den Dateinamen ziemlich einfach mit einer benannten Gruppenregexp extrahieren:

const regExpFilename = /filename="(?<filename>.*)"/;

const filename: string | null = regExpFilename.exec(contentDispositionHeader)?.groups?.filename ?? null;

Ich weiß, dass ich hier etwas vom Thema abweiche, da OP keine Anführungszeichen um den Dateinamen hat, aber immer noch teilt, falls jemand auf das gleiche Muster stößt wie ich gerade

Benutzer-Avatar
J Scott

Wenn Sie den Dateinamen erhalten und sowohl diese seltsamen URL-codierten UTF-8-Header als auch die ASCII-Header unterstützen möchten, können Sie so etwas verwenden

public getFileName(disposition: string): string {
    const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; ?|$)/i;
    const asciiFilenameRegex = /^filename=(["']?)(.*?[^\\])\1(?:; ?|$)/i;

    let fileName: string = null;
    if (utf8FilenameRegex.test(disposition)) {
      fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
    } else {
      // prevent ReDos attacks by anchoring the ascii regex to string start and
      //  slicing off everything before 'filename="
      const filenameStart = disposition.toLowerCase().indexOf("filename=");
      if (filenameStart >= 0) {
        const partialDisposition = disposition.slice(filenameStart);
        const matches = asciiFilenameRegex.exec(partialDisposition );
        if (matches != null && matches[2]) {
          fileName = matches[2];
        }
      }
    }
    return fileName;
}

Ein paar Anmerkungen:

  1. Dadurch wird der Wert des UTF-8-Dateinamens, falls festgelegt, über den ASCII-Namen übernommen
  2. Beim Herunterladen kann Ihr Browser den Namen weiter ändern, um bestimmte Zeichen zu ersetzen, wie z "mit _ (Chrom)
  3. Das ASCII-Muster funktioniert am besten für Dateinamen in Anführungszeichen, unterstützt jedoch Werte ohne Anführungszeichen. In diesem Fall wird der gesamte Text nach dem behandelt filename= und vor dem entweder dem nächsten ; oder das Ende des Header-Werts als Dateiname.
  4. Pfadinformationen werden dadurch nicht bereinigt. Wenn Sie die Datei von einer Website speichern, ist dies die Aufgabe des Browsers, aber wenn Sie dies im Kontext einer Node-App oder ähnlichem verwenden, stellen Sie sicher, dass Sie die Pfadinformationen pro Betriebssystem bereinigen und nur den Dateinamen belassen. oder ein präparierter Dateiname könnte verwendet werden, um eine Systemdatei zu überschreiben (denken Sie an einen Dateinamen wie ../../../../../../../path/to/system/files/malicious.dll)

MDN-Content-Disposition-Header

  • Der ASCII-Dateiname muss nicht in einfache oder doppelte Anführungszeichen gesetzt werden.

    – MoonStom

    30. Juli 2021 um 0:26 Uhr

  • @MoonStom Das ist ein guter Punkt, ich werde aktualisieren.

    – J Scott

    30. Juli 2021 um 17:27 Uhr

  • Dies ist eine großartige Antwort, ich musste nur eine Änderung vornehmen und hinzufügen i bis zum Ende der ersten Regex, weil mein Header als zurückkam filename*=utf-8 nicht UTF-8.

    – Colemann

    1. September 2021 um 13:59 Uhr

  • Das dot und hyphen müssen in diesem Fall nicht in einem Zeichensatz maskiert werden. Also verwenden [.-] Anstatt von [\.\-]

    – Steven Spungin

    19. Januar um 16:15 Uhr


  • Das wusste ich nicht, aber ich bin auch der Meinung, dass Sonderzeichen maskiert werden sollten, auch wenn sie in diesem Zusammenhang keine Sonderzeichen sind; es macht den Code lesbarer, was ich auch außerhalb von Stack Overflow bevorzuge

    – J Scott

    19. Januar um 17:17 Uhr

Benutzer-Avatar
Andrea Ligios

Versuchen Sie diese Lösung:

var contentDisposition = xhr.getResponseHeader('Content-Disposition');
var startIndex = contentDisposition.indexOf("filename=") + 10; // Adjust '+ 10' if filename is not the right one.
var endIndex = contentDisposition.length - 1; //Check if '- 1' is necessary
var filename = contentDisposition.substring(startIndex, endIndex);
console.log("filename: " + filename)

  • Der ASCII-Dateiname muss nicht in einfache oder doppelte Anführungszeichen gesetzt werden.

    – MoonStom

    30. Juli 2021 um 0:26 Uhr

  • @MoonStom Das ist ein guter Punkt, ich werde aktualisieren.

    – J Scott

    30. Juli 2021 um 17:27 Uhr

  • Dies ist eine großartige Antwort, ich musste nur eine Änderung vornehmen und hinzufügen i bis zum Ende der ersten Regex, weil mein Header als zurückkam filename*=utf-8 nicht UTF-8.

    – Colemann

    1. September 2021 um 13:59 Uhr

  • Das dot und hyphen müssen in diesem Fall nicht in einem Zeichensatz maskiert werden. Also verwenden [.-] Anstatt von [\.\-]

    – Steven Spungin

    19. Januar um 16:15 Uhr


  • Das wusste ich nicht, aber ich bin auch der Meinung, dass Sonderzeichen maskiert werden sollten, auch wenn sie in diesem Zusammenhang keine Sonderzeichen sind; es macht den Code lesbarer, was ich auch außerhalb von Stack Overflow bevorzuge

    – J Scott

    19. Januar um 17:17 Uhr

Benutzer-Avatar
Haxpanel

Es gibt ein npm-Paket, das die Arbeit erledigt: Inhaltsdisposition

  • Scheint im Browser nicht zu funktionieren.

    – UltimaWaffe

    28. Januar 2021 um 7:52 Uhr

  • Und der Autor von [github.com/jshttp/content-disposition/issues/… doesn’t seem to want to remove nodejs deps. Pretty much all the npm packages I could find use at least the path package from nodejs.

    – contrebis

    Jul 1, 2021 at 15:54

  • There is also content-disposition-header which works with both browsers and Node.js

    – fservantdev

    Feb 7 at 12:31

1208050cookie-checkSo erhalten Sie den Dateinamen von der Inhaltsdisposition

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy