如何从content-disposition获取文件名

Aru*_*van 33 javascript ajax filenames file-type content-disposition

我下载文件作为ajax的响应.如何从内容处理中获取文件名和文件类型,并为其显示缩略图.我有很多搜索结果,但找不到正确的方法.

$(".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);     
        }
    });
Run Code Online (Sandbox Code Playgroud)

控制台输出:inline; filename=demo3.png

Win*_*ier 66

这是我在某个时候使用它的方式.我假设您提供附件作为服务器响应.

我从我的REST服务中设置了这样的响应头 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, '');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:编辑答案以适合您的问题 - 使用单词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, '');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更多这里

  • 我不敢相信 JavaScript 有时是多么的丑陋和丑陋...... (7认同)
  • 此解决方案不适用于以下情况:**附件;文件名*=UTF-8''文件名.txt**。使用此正则表达式,文件名将为 **UTF-8filename.txt**。 (4认同)
  • 要匹配这样的 utf8 模式: `dis = "attachment; filename*=UTF-8''filename.pdf"` 尝试 `/filename\*?=([^']*'')?([^;] *)/.exec(dis)[2]` (3认同)
  • 您的正则表达式将与filenameXXX = ......或inlineXXXX = ...匹配。 (2认同)
  • 我认为最好使用 `disposition.startsWith("attachment")` 而不是 `disposition.indexOf('attachment') !== -1`,因为文件名可能包含 _attachment_ (2认同)

J S*_*ott 33

如果你想获取文件名并支持那些奇怪的 url 编码的 UTF-8 标头和 ascii 标头,你可以使用类似的东西

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;
}
Run Code Online (Sandbox Code Playgroud)

一些注意事项:

  1. 这将采用 UTF-8 文件名的值(如果设置)而不是 ascii 名称
  2. 下载后,您的浏览器可能会进一步更改名称以替换某些字符,例如", 为_(Chrome)
  3. ascii 模式最适合带引号的文件名,但支持不带引号的值。在这种情况下,它将标头值的下filename=一个或;结尾之后和之前的所有文本视为文件名。
  4. 这不会清除路径信息。如果您要从网站保存文件,则这是浏览器的工作,但如果您在节点应用程序或类似内容的上下文中使用此文件,请务必清理每个操作系统的路径信息并仅保留文件名或精心设计的文件名可能用于覆盖系统文件(想象一个像这样的文件名../../../../../../../path/to/system/files/malicious.dll

MDN 内容处置标头

  • 这是一个很好的答案,我只需要做一个更改并将“i”添加到第一个正则表达式的末尾,因为我的标头返回为“filename*=utf-8”而不是“UTF-8”。 (2认同)

Shi*_*uri 16

这是对 marjon4 答案的改进。

选择答案的一种更简单的方法是使用 split ;

var fileName = xhr.getResponseHeader('content-disposition').split('filename=')[1].split(';')[0];
Run Code Online (Sandbox Code Playgroud)

注意:如果您的文件名本身包含分号 (;),则此解决方案可能无法按预期工作

  • 这是一种幼稚的做法,不推荐。如果文件名包含分号,这可能会返回不正确的结果。缺少对 `filename*=UTF-8''` 的支持。 (2认同)
  • 该解决方案适用于 ```filename*=UTF-8' '``` 格式您可能引用的整个格式如下 ```content-disposition: "attachment; filename=document.pdf; filename*= UTF-8''文档.pdf"```. 请先尝试理解并回答后再说不行!是的,对于所有技术细节,如果文件名本身包含分号,则此解决方案将不起作用。但在大多数情况下,文件名不包含分号,因此考虑到这个借口,它对我来说效果很好!(仍在我的回答中添加注释。) (2认同)
  • 当文件名本身包含“filename=”时,它也不适用于边缘情况。 (2认同)
  • 我会添加 .replaceAll('"',''),否则它似乎会因空格名称而失败 (2认同)

mar*_*on4 13

或者只是:

var fileName = xhr.getResponseHeader('Content-Disposition').split("filename=")[1];
Run Code Online (Sandbox Code Playgroud)

  • 不适用于以下格式: `content-disposition: "attachment; filename=document.pdf; filename*=UTF-8''document.pdf"` (7认同)
  • 添加了一个答案来解决@AlexM提到的问题 (2认同)

max*_*992 7

在我的情况下,标题如下所示:

attachment; filename="test-file3.txt"
Run Code Online (Sandbox Code Playgroud)

因此,我能够使用命名组正则表达式很容易地提取文件名:

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

const filename: string | null = regExpFilename.exec(contentDispositionHeader)?.groups?.filename ?? null;
Run Code Online (Sandbox Code Playgroud)

我知道我在这里有点偏离主题,因为 OP 没有在文件名周围加上引号,但仍然共享以防有人遇到与我刚刚做的相同的模式