簡體   English   中英

如何從內容處置中獲取文件名

[英]How to get file name from content-disposition

我下載了一個文件作為 ajax 的響應。 如何從content-disposition獲取文件名和文件類型並為其顯示縮略圖。 我得到了很多搜索結果,但找不到正確的方法。

$(".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);     
    }
});

控制台輸出:

inline; filename=demo3.png

這是我以前使用它的方式。 我假設您將附件作為服務器響應提供。

我從我的 REST 服務response.setHeader("Content-Disposition", "attachment;filename=XYZ.csv");設置這樣的響應頭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, '');
        }
    }
}

編輯:編輯答案以適合您的問題 - 使用詞inline而不是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, '');
        }
    }
}

更多在這里

這是對 marjon4 答案的改進。

選擇答案的一種更簡單的方法是使用 split ;

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

注意:如果您的文件名本身包含分號 (;),則此解決方案可能無法按預期工作

或者只是:

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

在我的情況下,標題如下所示:

attachment; filename="test-file3.txt"

因此,我能夠使用命名組正則表達式很容易地提取文件名:

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

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

我知道我在這里有點偏離主題,因為 OP 沒有在文件名周圍加上引號,但仍然共享以防有人遇到與我剛剛做的相同的模式

試試這個解決方案:

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)

有一個 npm 包可以完成這項工作: content-disposition

如果你想獲得文件名並支持奇怪的 url 編碼的 UTF-8 和 ascii 頭,你可以使用這樣的東西

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

    let fileName: string = null;
    if (utf8FilenameRegex.test(disposition)) {
      fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
    } else {
      const matches = asciiFilenameRegex.exec(disposition);
      if (matches != null && matches[2]) {
        fileName = matches[2];
      }
    }
    return fileName;
}

一些注意事項:

  1. 這將采用 UTF-8 文件名的值(如果已設置)覆蓋 ascii 名稱
  2. 您的瀏覽器可能會進一步更改名稱以替換某些字符,例如" ,使用_ (Chrome)
  3. ascii 模式最適用於帶引號的文件名,但支持不帶引號的值。 在這種情況下,它會處理filename=和下一個;之前的所有文本; 或標題值的結尾作為文件名。

MDN 內容處置標頭

如果您不使用多部分主體,則可以使用此功能。 它從 Content-Disposition 標頭值(字符串如: inline; filename=demo3.png )中提取文件名並根據需要進行解碼。

const getFileNameFromContentDisposition = disposition => { 
    if (disposition
        && (disposition.startsWith('attachment') || disposition.startsWith('inline'))
    ) {
        let filename = disposition.startsWith('attachment')
            ? disposition.replace("attachment;", "")
            : disposition.replace("inline;", ""); //replaces first match only
        filename = filename.trim();
        if (filename.startsWith("filename=")) {
            filename = filename.replace("filename=", "");
            filename = filename.slice(1, filename.length - 1); //remove quotes
        } else if (filename.startsWith("filename*=")) {
            filename = filename.replace("filename*=", "")
                .split("''").slice(1).join("''"); //remove encoding and ''
            filename = decodeURIComponent(filename);
        }
        return filename;
    }
}

函數的結果可以拆分為名稱和擴展名,如下所示:

let name = getFileNameFromContentDisposition("inline; filename=demo.3.png").split(".");
let extension = name[name.length - 1];
name = name.slice(0, name.length - 1).join(".");
console.log(name); // demo.3
console.log(extension); //png

例如,您可以使用 svg 顯示縮略圖:

let colors = {"png": "red", "jpg": "orange"};
//this is a simple example, you can make something more beautiful
let createSVGThumbnail = extension => `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" viewBox="0 0 18 20">
    <rect x="0" y="0" width="18" height="20" fill = "#FAFEFF"/>
    <rect x="0" y="7" width="18" height="6" stroke="${colors[extension] || "blue"}" fill = "${colors[extension] || "blue"}"/>
    <text stroke = "white" fill = "white" font-size = "6" x = "0" y = "12.5" textLength = "18">${extension.toUpperCase()}</text>
</svg>`;

...

//You can use it as HTML element background-image
let background = "data:image/svg+xml;base64," + btoa(new TextDecoder().decode(createSVGThumbnail("png"))); 

(文件在瀏覽器中以二進制格式保存。文件名在客戶端的 Network/header/Content-Disposition 中,我們需要獲取文件名)

In Server-side code:
node js code-
    response.setHeader('Access-Control-Expose-Headers','Content-Disposition');
    response.download(outputpath,fileName);   

In client-side code:
1)appComponent.ts file
import { HttpHeaders } from '@angular/common/http';
this.reportscomponentservice.getReportsDownload(this.myArr).subscribe((event: any) => {
 var contentDispositionData= event.headers.get('content-disposition');
 let filename = contentDispositionData.split(";")[1].split("=")[1].split('"')[1].trim()
 saveAs(event.body, filename); 
});

2) service.ts file
import { HttpClient, HttpResponse } from '@angular/common/http';
getReportsDownload(myArr): Observable<HttpResponse<Blob>> {
 console.log('Service Page', myArr);
 return this.http.post(PowerSimEndPoints.GET_DOWNLOAD_DATA.PROD, myArr, {
  observe: 'response',
  responseType: 'blob'
 });
}

在我的情況下沒有在stackoverflow上找到任何響應。 我收到了這樣的內容處理: 內聯; 文件名* = UTF-8''Dossier%20de%20diagnostic%20technique.pdf

我修改了正則表達式來處理UTF-8字符串(如果存在): var regex = / filename [^; = \\ n] =(UTF-8(['“] ))?(。*)/;

這是我的功能:

function getFileNameByContentDisposition(contentDisposition){
    var regex = /filename[^;=\n]*=(UTF-8(['"]*))?(.*)/;
    var matches = regex.exec(contentDisposition);
    var filename;

    if (matches != null && matches[3]) { 
      filename = matches[3].replace(/['"]/g, '');
    }

    return decodeURI(filename);
}

編輯:我沒有那么多測試。 不要忘記在NodeJS代碼中使用try / catch包裝它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM